Lately, I’ve had to find a hosting server to replace the server we rented for delire.party,
our self-hosting collective of friends. Indeed, OVH decided, with no extra explanations, to
decomission our Kimsufi server at the end of the year, and to have us pay a few euros more per
month until then. This kind of practices irritates me, so I’ve decided to pull out
the plug (metaphorically speaking — the OVH server will still be online for the time of the
migration) and have our next server live at Hetzner.
Hetzner is a German company, they’ve been relying on renewable energy for a
while, and they have this interesting system
of server auctions, with prices lowering until a server has been rented out. For a regular human
being, that would mean checking the website multiple times a day to find a cheap server with the
right specification. I, for one, am a nerd, so I’ve looked for ways to automate this.
There are a few scripts for this on the Internet, but I made a relatively short one that was
perfectly suited for my constraints. I wanted to only see servers with a price tag less than 50€
per month, and at least 2TB of NVME storage. I also wanted email notifications, so that I can stay
in the comfort of my email client to check out the new deals. The script doesn’t account for deals
it’s already seen, but using it for three days (running it once per day) was sufficient to find a
satisfying deal, so I didn’t even have to bother implementing that.
The script is written in JavaScript (based on the one I’ve taken inspiration from), and it has two
dependencies: request
to run the HTTP requests, and nodemailer
to send me the email.
var nodemailer = require("nodemailer");
var request = require("request");
var dataUrl = 'https://www.hetzner.com/_resources/app/jsondata/live_data_sb.json';
var config = {
smtp_host: "mail.example.com",
smtp_port: null,
smtp_username: null,
smtp_password: null,
smtp_accept_unauthorized: true,
email_from: "hetzner-deals@example.com",
email_to: "your-email@example.com",
}
if (!config.smtp_host) {
console.error("Please specity SMTP host");
process.exit(1);
}
if (!config.email_to) {
console.error("Please specify the email address to send notifications to");
process.exit(1);
}
var transporter = nodemailer.createTransport({
host: config.smtp_host,
port: config.smtp_port,
auth: {
user: config.smtp_username,
pass: config.smtp_password
},
tls: {
rejectUnauthorized: !config.smtp_accept_unauthorized
}
});
var jar = request.jar();
request = request.defaults({ jar: jar });
request.get(dataUrl, (error, resp, body) => {
if (error || resp.statusCode !== 200) {
console.error("Error: " + error);
console.error("Response code: " + resp.statusCode);
process.exit(2);
}
let json = JSON.parse(body);
let results = [];
for (let s of json.server) {
let sumNvme = s.serverDiskData.nvme.reduce((a, b) => a + b, 0);
let monthlyPrice = s.hourly_price * 24 * 31;
monthlyPrice += 2.02;
monthlyPrice = ((100 * monthlyPrice) | 0) / 100;
if (sumNvme >= 2000 && monthlyPrice < 50) {
results.push(`- ${s.id}:`);
results.push(` RAM=${s.ram_size}GB`);
results.push(` NVME=${sumNvme}GB`);
results.push(` PRICE=~${monthlyPrice}€`);
results.push(` (${s.information})`);
results.push('');
}
}
var mailOptions = {
from: config.email_from,
to: config.email_to,
subject: "Hetzner Server deal found",
text: "Found deals:\n\n" + results.join('\n'),
};
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
console.error("Error sending email notification: " + error);
process.exit(3);
} else {
console.log('Email notification sent: ' + info.response);
}
});
});
Hope this may be useful to some of you too!
Comments
You can comment this post on the Fediverse by answering
this toot.
Since the Fediverse is decentralized, you can use your existing account hosted by any
Mastodon server or compatible platform if you don't have an account on this one. Known
non-private replies are displayed below.
More details on the inner workings here
and here.