This website is now live on a small Hetzner cloud instance.
- Hugo
- forgejo
- forgejo-runner
- release
- webhook
- nginx
Hugo
I chose Hugo for my static site generator. It is written in Go, a language I don't really know very well. The previous iteration of this site used the built-in Jekyll that came with the website tools over at Soverin.
The reason I chose Hugo over something else like Jekyll which is written in Ruby, or another site generator in some other language I know and/or like, is very simple: Hugo is available as an APT package in Debian, which means it's easy for me to set up something to generate my site. It's not the latest version, but I'm fine with that.
Pipeline
The website is hosted in a git repo, so adding a new article or tweaking something in the UI is just a matter of fiddling a bit in the repo, and committing the changes.
I then push those changes to my forgejo instance, and let a CI pipeline take care of building a release and deploying that onto my server.
The CI runner is forgejo runner, running a docker container on the same server as my forgejo instance. It works very similar to how a GitHub Action pipeline would, except I had to figure out how to get the pieces to talk to each other.
When the new version of the site is built, the workflow creates a "release" on the repo and pushes the built version of the site there. The repo is configured to send a webhook when a new release is published. Webhooks use the webhook
package from APT, which is another golang project.
Since I'm hosting the site on the same server as the forgejo instance, the webhook is sent to localhost
, and since that is locally on the same machine and none of those ports are exposed through the firewall, I haven't bothered with authenticating the webhook.
Isn't all this a bit overkill just in order to host a static website?
Yes, but I wanted to learn.
I could totally have just run hugo
locally and then rsync --delete -r ./public/ martin.frost.ws:/path/to/my/webroot
and be done with it.
But then I would have missed a learning opportunity.
Also, I of course want to track my changes, so a git repo is a great way to do that. I could have used GitHub, of course, but I want to try hosting my own thing, and I feel like MicroSoft has a bit too big piece of the developer tooling pie. So I set up a forgejo instance.
I could have pushed the changes to the git hosting and have that send a webhook to the server, and built the site on the server directly. But I didn't really feel like scripting something to clone a git repo and running a build directly on the server, and that's probably not how I would have set it up if I wanted to create something on a larger scale, so I went ahead to learn how to set up a forgejo runner as well.
So, a bit of sysadmining later (and a lot of reading error messages), I have a runner for my git repos that can run tests and whatever I feel like in a container when I push changes to the repo. In the case of this website, it will run a debian container that builds the site, creates a release with the built site as a tarball, and publishes that on the repo. When the release gets published, forgejo sends a webhook locally to the server, the server downloads and extracts the tarball in a directory and updates a symlink to point to the current release.
The site is then served by nginx. There's not really much to say about that part.
Conclusion
I am overdoing this by piecing together a whole bunch of tooling in order to host a static website. But it was a learning experience. Now I know how to do that. And it was fun!