Ilari Sorvali

Making a static website with Go, Part 3

How is the website deployed? Great question.

Go handily compiles into a single native binary, so runtime dependencies are practically none. The binary just expects it to be pointed to directories containing Markdown files to be processed into posts and an image directory that it serves as a static image directory for the posts to use.

The binary could be run as just a binary, but I've opted to run it inside a Podman container, as that makes service management a bit easier. I have a Linux VPS on Hetzner that acts as the host. On the host systemd is used to orchestrate various Podman containers as services defined as Quadlets. Quadlets are a way to define and run Podman workloads under systemd control, same systemd ecosystem commands can be used to start, stop, monitor and inspect the containers like other systemd units. The definition of the website service as a Quadlet looks like this:

[Unit]
Description=Personal website
After=network-online.target

[Container]
Image=ghcr.io/ilarisorvali/go-website:latest
PublishPort=127.0.0.1:9000:9000
Volume=%h/saitti/blog:/app/markdown:Z
Volume=%h/saitti/blog/images:/app/images:Z
Pull=newer

[Service]
Restart=always

[Install]
WantedBy=default.target

If you're familiar with systemd, this looks almost exactly like a normal systemd unit file, because that's what it basically is. The image for the container is built on Github on main push/merge, but it could be built and hosted on the hosting server too. I just think hosting and building on Github is a cleaner way to manage the images, so the host is only responsible for running the deployed image. There's also a separate Caddy instance that routes traffic to the container from outside.

The deployment is a very manual job as of now, I have to push code changes and new posts to Github, pull the post data (from a private post Markdown repo) to the Linux host and just restart the container service to get newest changes to the website. The process could be automated, but I haven't implemented it yet.

Podman and systemd can also handle automatic container updates. Podman has an auto-update mechanism that runs on a systemd timer and checks whether a container's image has been updated in its registry. If a newer image is found, Podman pulls it and recreates the container using the new image.

So at some point, the deployment process should look something like this: push changes to GitHub, GitHub builds the new image, and the VPS notices the new image and deploys it automagically. Much less manual SSHing and other hassle.