blog-static/content/blog/blog_with_nix.md

4.4 KiB

title date expirydate draft tags
Declaratively Deploying Multiple Blog Versions with NixOS and Flakes 2021-10-23T18:01:31-07:00 2021-10-23T18:01:31-07:00 true
Hugo
Nix

Prologue

You can skip this section if you'd like.

For the last few days, I've been stuck inside of my room due to some kind of cold or flu, which or {{< sidenote "right" "pcr-note" "may or may not be COVID™." >}} The results of the PCR test are pending at the time of writing. {{< /sidenote >}} In seeming correspondence with the progression of my cold, a thought occured in the back of my mind: "Your blog deployment is kind of a mess". On the first day, when I felt only a small tingling in my throat, I waved that thought away pretty easily. On the second day, feeling unwell and staying in bed, I couldn't help but start to look up Nix documentation. And finally, on the third day, between coughing fits and overconsumption of oral analgesic, I got to work.

In short, this post is the closest thing I've written to a fever dream.

The Constraints

I run several versions of this site. The first is, of course, the "production" version, hosted at the time of writing on danilafe.com and containing the articles that I would like to share with the world. The second is a version of this site on which drafts are displayed - this way, I can share posts with my friends before they are published, get feedback, and even just re-read what I wrote from any device that has an internet connection. The third is the Russian version of my blog. It's rather empty, because translation is hard work, so it only exists so far as another "draft" website.

My build process (a derivative of what I describe in [rendering mathematics on the back end]({{< relref "./backend_math_rendering.md" >}})) is also fairly unconventional. When I developed this site, the best form of server-side mathematics rendering was handlded by KaTeX, and required some additional work to get rolling (specifically, I needed to write code to replace sections of LaTeX on a page with their HTML and MathML versions). There may be a better way now, but I haven't yet performed any kind of migration.

Currently, only my main site is behind HTTPS. However, I would like for it to be possible to adjust this, and possibly even switch my hosts without changing any of the code that actually builds my blog.

Why Flakes

This article is about using Nix Flakes to manage my configuration. But what is it that made me use flakes? Well, two things:

  • Adding custom packages. The Nix code for my blog provides a package / derivation for each version of my website, and I want to use these packages in my configuration.nix so that I can point various Nginx virtual hosts to each of them. This is typically done using overlays, but I need a clean way to let my system configuration pull in my blog overlay (or blog packages); flakes solve this issue my letting me specify a blog flake, and pull it in as one of the inputs.
  • Versioning. My process for deploying new versions of the site prior to flakes boiled down to fetcing the latest commit from the master branch of my blog repository, and updating the default.nix file with that commit. This way, I could reliably fetch the version of my site that I want published. Flakes do the same thing: the flake.lock file contains the hashes of the Git-based dependencies of a flake, and thus prevents builds from accidentally pulling in something else. However, unlike my approach, which relies on custom scripts and extra tools such as jq, the locking mechanism used by flakes is provided with standard Nix tooling. Using Flakes also guarantees that my build process won't break with updates to Hugo or Ruby, since the nixpkgs version is stored in flake.lock, too.

The Final Result

Here's the relevant section of my configuration:

{{< codelines "Nix" "server-config/configuration.nix" 42 59 >}}

I really like how this turned out for three reasons. First, it's very clear from the configuration what I want from my server: three virtual hosts, one with HTTPS, one with drafts, and one with drafts and in Russian. Second, there's plenty of code reuse. I'm using two builder functions, english and russian, but under the hood, the exact same code is being used to run Hugo and all the necessay post-processing. Finally, all of this can be used pretty much immediately given my blog flake, which reduces the amount of glue code I have to write.