How to set up a nix-backed blog (ft. Hugo, Gitlab CI/CD and Netlify)
This goes over how I set up a static website using Nix, Hugo, Gitlab CI/CD and Netlify.
The argument for having a nix-backed blog is the usual argument for using nix to build anything - by leveraging the nix package manager to build the dependencies of a project, the project should be completely portable and reproducible no matter where you build it. Nix philosophy aside, I wanted this website to be a nix-backed project because I’m running NixOS on my daily driver and I’m still getting the hang of using nix for development.
That said, here are the basic requirements for my blog:
- dependencies should be managed by nix
- source code should be in a private repo
- new blog posts (via commits) should be automatically published
First, have a blog
My starting point was this post from kalbas.it, where I grabbed the initial nix-shell script to bootstrap my hugo project. The og post includes a more detailed breakdown of how the script works and how to pin nixpkgs and a hugo theme of your choice to a specific commit so that it’s reproducible between builds.
My shell.nix
, which sits at the root of my project dir, ended up looking like this:
let
# See https://nixos.wiki/wiki/FAQ/Pinning_Nixpkgs for more information on pinning
nixpkgs = builtins.fetchTarball {
name = "nixpkgs-20.09"; # Store path name
url = https://github.com/NixOS/nixpkgs/archive/cd63096d6d887d689543a0b97743d28995bc9bc3.tar.gz; # Commit hash for nixpkgs 20.09 release
sha256 = "1wg61h4gndm3vcprdcg7rc4s1v3jkm5xd7lw8r2f67w502y94gcy"; # Hash obtained using `nix-prefetch-url --unpack <url>`
};
in
{ pkgs ? import nixpkgs {} }:
with pkgs;
let
hugo-theme-cactus = runCommand "hugo-theme-cactus" {
pinned = builtins.fetchTarball {
name = "hugo-theme-cactus-2020-12-28"; # Store path name
url = https://github.com/monkeyWzr/hugo-theme-cactus/archive/f3fe7410c3839e7685812600dc8d2ae54de85d4e.tar.gz;
sha256 = "1mpqhsbgxvcg0z5jnmcxyyk2rhk3w6bm16cwbyp77x7rq7ggqr3x"; # Hash obtained using `nix-prefetch-url --unpack <url>`
};
patches = [];
preferLocalBuild = true;
}
''
cp -r $pinned $out
chmod -R u+w $out
for p in $patches; do
echo "Applying patch $p"
patch -d $out -p1 < "$p"
done
'';
in
mkShell {
buildInputs = [
hugo
];
shellHook = ''
mkdir -p themes
ln -snf "${hugo-theme-cactus}" themes/hugo-theme-cactus
'';
}
Now to generate the initial instance of my blog, I run:
$ nix-shell --run "hugo new site coolsite"
// move generated dirs into the project root
$ cp -r coolsite/* . & rm -rf coolsite
You can “hugo serve” (inside of a nix shell!) to see your website in action locally.
Continuously deliver this thing
Revisiting the goal, I want to set things up so that publishing new blog posts to the internet requires minimal effort. To achieve this I’m using Gitlab for CI/CD and Netlify for hosting. Gitlab because I wanted to host my code from a private repo (this is paid feature for Github Pages apparently?), and Netlify because they have integration with Gitlab and netlify-cli
is supported in the nixpkgs version I point at.
Setting up Gitlab CI/CD
To configure CI/CD, I have a .gitlab-ci.yml
in the root of my project that looks like this:
image: nixos/nix
stages:
- build
- deploy
cache:
paths:
- /nix/store
build:
stage: build
script:
- nix-shell --command "hugo"
artifacts:
untracked: true
paths:
- public/
deploy:
stage: deploy
script:
- nix-shell -p netlify-cli --command "netlify deploy --auth=$NETLIFY_AUTH_TOKEN --dir=public --site=$APP_ID --prod"
when: on_success
This describes a nixos-backed build image with two stages: build and deploy. Each call to nix-shell will first evaluate the shell.nix
we set up earlier, which ensures that the exact version of nixpkgs and the hugo theme are used with each build.
The build stage calls “hugo” which generates the public
directory. The deploy step uses the netlify
cli to publish the site described in public/
to netlify.
Before this can work, you’ll have to set up the $NETLIFY_AUTH_TOKEN
and $APP_ID
environment variables in Gitlab.
Pointing at Netlify
First you’ll want to create a Netlify account and link your Gitlab repo if you haven’t already1.
You can grab your auth token by running the netlify-cli locally. In your nix-shell, run:
$ nix-shell -p netlify-cli --command "netlify login"
You should now be able to grab your auth token from your local netlify config file, ie the token
line in ~/.netlify/config
.
The last variable you need is the app id of your netlify site, which you can grab from the “General” page of your site’s dashboard on netlify. These values can now be plugged into Gitlab as $NETLIFY_AUTH_TOKEN and $APP_ID2.
You’re done!
You should now be able to push a commit and watch Gitlab CI/CD build and deploy your website on its own. All backed by nix! Noice.