Finih up draft of the Nix Blog article

This commit is contained in:
Danila Fedorin 2022-04-10 00:53:35 -07:00
parent dc3f086b9d
commit fe1c05fe46

View File

@ -1,6 +1,6 @@
--- ---
title: "Declaratively Deploying Multiple Blog Versions with NixOS and Flakes" title: "Declaratively Deploying Multiple Blog Versions with NixOS and Flakes"
date: 2021-10-23T18:01:31-07:00 date: 2022-04-10T00:24:58-07:00
draft: true draft: true
tags: ["Hugo", "Nix"] tags: ["Hugo", "Nix"]
--- ---
@ -32,18 +32,15 @@ re-read what I wrote from any device that has an internet connection. The third
version of my blog. It's rather empty, because translation is hard work, so it only exists version of my blog. It's rather empty, because translation is hard work, so it only exists
so far as another "draft" website. 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 handled 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 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 adjust this, and possibly even switch my hosts without changing any of the code that actually
builds my blog. builds my blog.
I wanted to be able to represent all of this complexity in my NixOS configuration file, and
that's what this post is about!
### Why Flakes ### Why Flakes
This article is about using Nix Flakes to manage my configuration. But what is it that made This article is about using Nix flakes to manage my configuration. But what is it that made
me use flakes? Well, two things: me use flakes? Well, two things:
* __Adding custom packages__. The Nix code for my blog provides a package / derivation for each * __Adding custom packages__. The Nix code for my blog provides a package / derivation for each
@ -52,7 +49,7 @@ me use flakes? Well, two things:
overlays; however, how should my system configuration get my overlay Nix expression? I would overlays; however, how should my system configuration get my overlay Nix expression? I would
like to be able to separate my build-the-blog code from my describe-the-server code, and like to be able to separate my build-the-blog code from my describe-the-server code, and
so I need a clean way to let my system access the former from the latter. so I need a clean way to let my system access the former from the latter.
flakes solve this issue my letting me specify a blog flake, and pull it in as one flakes solve this issue by letting me specify a blog flake, and pull it in as one
of the inputs. of the inputs.
* __Versioning__. My process for deploying new versions of the site prior to flakes boiled down to fethcing * __Versioning__. My process for deploying new versions of the site prior to flakes boiled down to fethcing
the latest commit from the `master` branch of my blog repository, and updating the `default.nix` the latest commit from the `master` branch of my blog repository, and updating the `default.nix`
@ -98,7 +95,7 @@ There are a few things here:
because __they don't actually matter for the derivation itself__ -- they just aren't used because __they don't actually matter for the derivation itself__ -- they just aren't used
in the builder. However, attributes given to a derivation are accessible from "outside", in the builder. However, attributes given to a derivation are accessible from "outside",
and these settings will play a role later. and these settings will play a role later.
* Lines 10 through 14 deal with setting the base URL of the site. Hugo, my static site generator, * Lines 10 through 14 deal with setting the base URL of the site. Hugo
does not know how to interpret does not know how to interpret
the `--baseURL` option when a blog has multiple languages. What this means is that in the end, the `--baseURL` option when a blog has multiple languages. What this means is that in the end,
it is impossible to configure the base URL used in links from the command line, it is impossible to configure the base URL used in links from the command line,
@ -108,7 +105,7 @@ There are a few things here:
However, the configuration file only knows one base URL per language, and so it _doesn't_ know However, the configuration file only knows one base URL per language, and so it _doesn't_ know
when or when not to use the `drafts.` prefix. The `urlSub` variable is used in the builder. when or when not to use the `drafts.` prefix. The `urlSub` variable is used in the builder.
* On line 15, the `publicPath` variable is set; while single-language Hugo puts all the generated * On line 15, the `publicPath` variable is set; while single-language Hugo puts all the generated
HTML into the `public` folder, the multi-language configuration places them into `public/[language-code]`. HTML into the `public` folder, the multi-language configuration places it into `public/[language-code]`.
Thus, depending on the configuration, the builer needs to look in a different place for final output. Thus, depending on the configuration, the builer needs to look in a different place for final output.
This new `website` function is general enough to represent all my blog versions, but it's too low-level. This new `website` function is general enough to represent all my blog versions, but it's too low-level.
@ -153,7 +150,7 @@ describing my blog. However, by themselves, they aren't quite enough to clean
up my system configuration: for each of these blog versions, I'd need to add up my system configuration: for each of these blog versions, I'd need to add
an Nginx `virtualHosts` entry where I'd pass in the corresponding host (like `danilafe.com` or an Nginx `virtualHosts` entry where I'd pass in the corresponding host (like `danilafe.com` or
`drafts.danilafe.com`), configure SSL, and so on. At one point, too, all paths `drafts.danilafe.com`), configure SSL, and so on. At one point, too, all paths
in `/var` were by default mounted as read-only by NixOS, which meant that it was necessay in `/var` were by default mounted as read-only by NixOS, which meant that it was necessary
to tell `systemd` that `/var/www/challenges` should be writeable so that the SSL to tell `systemd` that `/var/www/challenges` should be writeable so that the SSL
certificate for the site could be properly renewed. Overall, this was a lot of detail certificate for the site could be properly renewed. Overall, this was a lot of detail
that I didn't want front-and-center in my server configuration. that I didn't want front-and-center in my server configuration.
@ -163,7 +160,8 @@ of the information required to configure Nginx. The virtual host, for instance,
is the same as `replaceUrl.to` (since I'd want the Nginx virtual host for a blog is the same as `replaceUrl.to` (since I'd want the Nginx virtual host for a blog
version to handle links within that version). The `ssl` ghost parameter corresponds version to handle links within that version). The `ssl` ghost parameter corresponds
precisely to whether or not a virtual host will need SSL (and thus ACME, and thus precisely to whether or not a virtual host will need SSL (and thus ACME, and thus
the `systemd` setting). the `systemd` setting). For each derivation built using `website`, I can access
the attributes like `ssl` or `host` to generate the corresponding piece of the Nginx configuation.
To make this _really_ nice, I wanted all of this to be "just another section of my To make this _really_ nice, I wanted all of this to be "just another section of my
configuration file". That is, I wanted to control my site deployment via regular configuration file". That is, I wanted to control my site deployment via regular
@ -232,7 +230,7 @@ the flake needs access to, and outputs are simply Nix expressions that the flake
The nice thing about flakes' inputs is that they can reference other flakes via Git. This means The nice thing about flakes' inputs is that they can reference other flakes via Git. This means
that, should I write a flake for my blog (as I am about to do) I will be able to reference its git URL that, should I write a flake for my blog (as I am about to do) I will be able to reference its git URL
in another flake, and Nix will automatically clone and import it. This helps provide the __adding custom packages__ in another flake, and Nix will automatically clone and import it. This helps achieve the __adding custom packages__
goal, since I can now easily write Nix expressions and reference them from my system configuration. goal, since I can now easily write Nix expressions and reference them from my system configuration.
Importantly, flakes track the versions of their inputs in a `flake.lock` file; this means that, unless explicitly told to do otherwise, Importantly, flakes track the versions of their inputs in a `flake.lock` file; this means that, unless explicitly told to do otherwise,
@ -249,14 +247,14 @@ Let's take a look at the inputs of my blog flake:
Two of these inputs are my blog source code, pulled from its usual Git host. They are marked as Two of these inputs are my blog source code, pulled from its usual Git host. They are marked as
`flake = false` (my blog is just a Hugo project!), and both require submodules to be fetched. One `flake = false` (my blog is just a Hugo project!), and both require submodules to be fetched. One
of them is set to the `localization` branch, once again because localization is not yet stabled of them is set to the `localization` branch, once again because localization is not yet stabilized
and thus not merged into my blog's `master` branch. The other three inputs are flakes, one of and thus not merged into my blog's `master` branch. The other three inputs are flakes, one of
which is just `nixpkgs`. The `flake-utils` flake provides some convenient functions for writing other which is just `nixpkgs`. The `flake-utils` flake provides some convenient functions for writing other
flakes, and `katex-html` is my own creation, a KaTeX-to-HTML conversion script that I use to post-process the blog. flakes, and `katex-html` is my own creation, a KaTeX-to-HTML conversion script that I use to post-process the blog.
So what outputs should this flake provide? Well, we've already defined a NixOS module for the blog, and we'd like So what outputs should this flake provide? Well, we've already defined a NixOS module for the blog, and we'd like
our flake to expose this module to the world. But the module alone is not enough; its configuration requires a list of our flake to expose this module to the world. But the module alone is not enough; its configuration requires a list of
packages created using our builders. But where does one procure such a list? The caller will need access to the builders packages created using our builders. Where does one procure such a list? The caller will need access to the builders
themselves. To make all of this work, I ended up with the following expression for my `outputs`: themselves. To make all of this work, I ended up with the following expression for my `outputs`:
{{< codelines "Nix" "blog-static-flake/flake.nix" 21 34 >}} {{< codelines "Nix" "blog-static-flake/flake.nix" 21 34 >}}
@ -284,4 +282,23 @@ And that's it for the blog flake! I simply push it to Git, and move on to actual
#### Using the Module #### Using the Module
In my server configuration (which is, itself, a flake), I simply list my `blog-static-flake` as one
of the inputs:
{{< codelines "Nix" "server-config/flake.nix" 4 4 >}}
Then, in the `modules` attribute, I include `blog.nixosModule`, making NixOS aware of its options and configuration.
The final little piece is to provide the `english` and `russian` builders to the system configuration;
this can be done using the `specialArgs` attribute. The whole `flake.nix` file is pretty short:
{{< codeblock "Nix" "server-config/flake.nix" >}}
Finally, in `configuration.nix`, taking `builders` as one of the inputs, I finally write what you saw above:
{{< codelines "Nix" "server-config/configuration.nix" 42 59 >}} {{< codelines "Nix" "server-config/configuration.nix" 42 59 >}}
### Wrapping Up
So there you have it, a flake-based blog deployment written in a declarative style. You can
check out both my [system configuration flake](https://dev.danilafe.com/Nix-Configs/server-config)
and my [blog flake](https://dev.danilafe.com/Nix-Configs/blog-static-flake) on my Git server.
If you want more, check out the articles by Xe and Yannik linked above. Thanks for reading!