How to set up a nix-backed blog, again (ft. flakes this time)
Now that my NixOS system is freshly flake’d, I want to figure out how to manage my Hugo blog project (ie this very computers.lel) using nix flakes rather than a shell.nix
+ channels. This will give me an opportunity to see how flakes for development differs from flakes for NixOS system management.
Making sense of my past mistakes
Here was my first go at building a nix-backed Hugo blog. Why did I make the blog source private? what was i hiding?? And why did I deploy through Netlify and not just publish a static Gitlab page? We may never know…
What I do know is that the channels-backed shell.nix
that defines the current development environment and is referenced in gitlab-ci.yml
will be replaced by a flake.nix
! And I’ll drop the extra hop to Netlify and publish directly as a Gitlab page.
Plan
- Make a
flake.nix
- Get a “build my blog” output working locally via
flake.nix
- Get
hugo server
running locally viaflake.nix
- Build & publish the blog using Gitlab Pages
1: Initial flake.nix
I’m going to start from a basic Nix flake in the root directory of my Hugo project and incrementally figure out what I need to add to it. Running:
nix flake init
generates the following “hello world” flake.nix
example:
|
|
This is a super minimal flake.nix
with nixpkgs
as the only input, and 2 outputs: a “hello” package and a “default” package. The hello
(or more specifically pkgs.x86_64-linux.hello
) package points to the existing GNU Hello package in nixpkgs. The default package, which also points back to hello
, is what gets used when you don’t specify a flake target during calls to nix run
, nix build
, etc.
2: Build a hugo blog with flake.nix
What I want to do is replace the “hello” package with something of my own - a “website” package that descries how to build my hugo site. But unlike the hello package (which references a preexisting hello in nixpkgs), I’ll have to define a custom derivation1 for website
, ie an expression describing how to build a thing in nix. I also know I’ll need to add my hugo theme as an input so that its version can be locked.
After looking at some examples of what other people did and reading through Wombat’s nix book, here’s what I cobbled together:
|
|
- L7-10: Providing my Hugo theme as an input, with L9 specifying that the git repo I’m referencing is just a regular repo (i.e. isn’t managed by a flake.nix)
- L13: Output function declarion2 with parameters passed using @-pattern3 argument set notation
- L14-16:
let...in
block to declare a shorthand fornixpkgs
aspkgs
within the output function; also so I don’t need to keep typingx86_64-linux
- L20: declaration of
website
package, orpackages.x86_64-linux.website
, using the functionstdenv.mkDerivation
4 - L24-25: buildPhase: symlink my hugo theme (via
inputs
param) into my hugo site’sthemes
folder - L26: buildPhase: run
hugo
command to generate apublic
folder5 to be picked up later ingitlab-ci.yml
deploy step - L28: installPhase: iiuc this phase needs some derivation output results to exist in the nix store path (stored in $out) ; afaict I don’t care about this for Gitlab Pages purposes but I’ll copy the public folder into here so mkDerivation can succeed running?
- L29: Declaration of
default
package (orpackages.x86_64-linux.default
) which points to thewebsite
package. This is why I putrec
(“recursive attribute set”6) on L19, because default refers an attribute that was defined in the same scope.
Running this with nix build
seems to work! I get a results
folder (with the contents of the public
folder I moved on L28) in my project directory that symlinks back to the nix store. This will be useful for calling within the .gitlab-ci.yml
file I’ll need to deploy a Gitlab Page, but it doesn’t let me develop my hugo site locally. For that I need to define a dev shell7!
Note: I saw a lot of examples using flake-utils
or flake-parts
to clean away output declaration boilerplate, which I’ll likely end up doing too. But for baby’s first flake.nix
I wanted to write things out the long way.
3: Run “hugo serve” in a dev shell with flake.nix
A development shell or devShell7 is an output hook for nix develop
, and replaces shell.nix
/nix-shell functionality. You can use it to describe a dev environment for running the thing you’re trying to build. In my case I want to be able to run hugo server
in my dev shell so that I can locally dev on my hugo site.
Starting at L33, I’ll use the stdenv function mkShell
8 to declare my shell:
|
|
- L34: List any pkgs I want available in the devShell - just hugo in my case
- L35-38: Set
shellHook
, which in my case sets up the hugo theme from my inputs
Now I can do:
nix develop
hugo server
:D
4. Publish to Gitlab
The .gitlab-ci.yaml
to drive the flakes-backed build and deploy to Gitlab Pages looks like this:
|
|
- L1: nix image!!
- L5: Run nix build (with flags to enable experimental flakes)
- L6: Okay wait-
this line kinda sucks because the git runner refuses to refer to an artifact that lives outside of the project’s own directory. The public
folder contents that exist in the nix store path of the website
package I just built on the previous line is an artefact that lives outside of the project’s own directory ;_; because it lives at /nix/store. To work around this, I have to recursive copy the contents (symlinked to the nix store within results/
) back into the current directory. Maybe another approach would be to do something like nix develop && hugo serve
but at this point I got sad and started googling GitHub Pages so I didn’t try it.
- L8: Declare public folder in current directory as an artifact, because apparently artefacts can’t live in the nix store -_-
- L8: The public folder isn’t tracked in my repo, so I specify that
Technically nix-backed, f u gitlab
So this works but the double copy step of the nix store results is kinda silly. But, this is good enough for now!
-
A derivation is Nix’s notion of a build plan. https://nix.dev/manual/nix/2.23/language/derivations ↩︎
-
https://mhwombat.codeberg.page/nix-book/#_named_functions_and_function_application named function syntax ↩︎
-
https://mhwombat.codeberg.page/nix-book/#at-patterns @-pattern in function declation syntax ↩︎
-
https://nixos.org/guides/nix-pills/19-fundamentals-of-stdenv https://nixos.org/manual/nixpkgs/stable/#sec-stdenv-phases ↩︎
-
https://docs.gitlab.com/ee/user/project/pages/introduction.html#customize-the-default-folder ↩︎
-
https://mhwombat.codeberg.page/nix-book/#rec-attrset when 2 rec ↩︎
-
https://nixos.wiki/wiki/Flakes#Output_schema Ctrl-f “devShells” output type under output schemas ↩︎ ↩︎
-
https://ryantm.github.io/nixpkgs/builders/special/mkshell/ ↩︎