I deployed this WriteFreely Blog on a Cheap Hetzner VM using OpenTofu (IaC)

Last year, I created an engineering-focused blog on hashnode.dev. It was easy, and it served its purpose. However, as time went on, I developed a few niggles with the blogging platform — mainly these:

My reasons for choosing a self-hosted WriteFreely are essentially the inverse of the above points, with a couple more:

How did I do it?

Now that I've outlined why, I can move on to the unashamedly geeky part of this post. My main objectives were to run Writefreely in a way that was both simple and cheap.

Simplicity

I got a lot of simplicity for free with this WriteFreely Docker image, which neatly encapsulates the initial configuration of WriteFreely as well as data migrations. The image doesn't leverage Writefreely's built-in automatic HTTPS. Luckily, another Go-based project, Caddy, does this, on top of being a solid reverse proxy.

Those of you who have used the likes of Apache or NGINX, but not Caddy, please take a moment to admire the two lines of configuration necessary to reverse proxy this blog:

simoncrowe.blog

reverse_proxy localhost:8080

Yes, this is all that's required to serve this blog and automatically provision TLS certificates using Let's Encrypt!

Frugality

The localhost origin in my Cadddyfile above isn't typical of a Docker-compose setup. It's a result of my trying to save money by not renting a public IPv4 address from Hetzner and only using a free IPv6 address. Caddy needed an internet-routable IPv6 address to get responses from Let's Encrypt's servers, and using the “host” network mode was the simplest way to achieve this.

The laptop I'm typing this on doesn't have an IPv6 address, so I couldn't SSH into the server, even if I wanted to. To get around this for HTTPS traffic, I used Cloudflare as a DNS registry and proxy. This means that simoncrowe.blog resolves to some of CloudFlare's v4 IPs. CloudFlare handles everything between the Hetzner IPv6 origin and its own dual-stack infrastructure, at no cost.

Trade-off time: My insistence on not paying the tiny IPv4 address fee has probably increased the complexity of this. The no SSH constraint is what motivated me to write a Terraform/OpenTofu module. Using the Hetzner web shell to configure even a simple setup like this would have been a miserable experience compared to SSH from the comfort of my laptop's terminal emulator. Because I've been lazy and put the database in the same machine as the HTTP server, I've already consigned the server to a long existence as a pet. Immutable Infrastructure is not happening here, so doing everything via the Hetzner web console and SSH would have been reasonable.

On the other hand, maybe my code will help someone else run their own WriteFreely. Here's the repo.

Cheap compute with a cloud API! What else can Hetzner do?

Since I managed to throw something functional together in a weekend, I'm wondering what one could do with Hetzner and IaC tooling like OpenTofu, given some time.

While I haven't explored their full networking and compute capabilities, the impression I got is that they'd be fine to run an early stage European startup's backend (with some caveats). Anything approaching a scale-up with global ambitions would be better off with a major public cloud provider. The main reason I say this is that they only have data centres in Germany, Finland, the US and Singapore (the latter two being rack-space in 3rd party data centres).

To me, Hetzner feels somewhere between a typical shared LAMP stack web hosting provider one might use for a Joomla/WordPress site and a mail server — and rudimentary AWS (mainly ec2, some s3 and recently a bit of route53). When creating VMs manually on Hetzner, you can install one piece of common software. Like the LAMP hosting, options include WordPress, but also more advanced things like Docker and Prometheus/Grafana. Unlike typical web hosting, you can provision infrastructure using an API, and you get root access to your servers. Rather quaintly, when a server spins up, you get an email with the default root password (luckily, sshd isn't running out of the box).

If I were a frugal European startup founder, the only thing that would stop me from choosing Hetzner is the lack of managed databases. The VMs could easily run stateless workloads where new software versions are rolled out smoothly using OpenTofu lifecycle policies. While one could run a database on such a VM, one would need to be very careful about backups and learn database administration. A tolerable middle ground might be running production databases using AWS RDS/Aurora in AWS regions geographically close to Hetzner locations; sure, there would be some extra latency, but it might be manageable.

I'll keep an eye on Hetzner. I'm impressed with how straightforward everything is with them. At the top of my wish list would be managed stateful services like Postgres and Kubernetes, a container registry, and guarantees around availability zones (high availability in general). Serverless versions of every imaginable thing, I can live without.