https://21csm.github.io/blog/feed.xml

Publishing a Zola site to GitHub Pages with Nix and GitHub Actions

2024-09-11

img

Escher, M.C. Metamorphosis II. 1939-1940. Woodcut printed from 20 blocks on 3 combined sheets. National Gallery of Art, Washington, D.C.

This article is a bit meta, but it explains how this blog is deployed and hosted. I use this setup because it's both powerful and convenient. Nix ensures that the site builds consistently on any machine. GitHub provides free hosting and automates the deployment process. Together, these tools make it easy to manage and update the site.

What is Zola?

Zola is a fast, flexible static site generator written in Rust. It takes your content, applies templates, and generates a complete static website ready to be served.

Why this Setup?

  1. Consistent Environments: Nix creates identical build environments on any machine.
  2. Automated Deployments: GitHub Actions handle builds and deployments automatically.
  3. Free Hosting: GitHub Pages hosts your site at no cost.
  4. Version Control: Your site's content is version-controlled with Git.
  5. Modularity: Content, site generation, build process, and deployment are separate, easing maintenance.

Prerequisites

  • A Nix Installation (The package manager or NixOS)
  • A GitHub Account
  • Basic familiarity with Git and command-line operations

Workflow

To better understand the entire process, let's look at a visual representation of the workflow:

  flowchart LR
    A[Local Development] --> B[GitHub Repository]
    B --> C[GitHub Actions]
    C --> D[Build with Nix]
    D --> E[Deploy to GitHub Pages]
    E --> F[Site Live]

    A -->|Push Changes| B
    C -->|Triggered on Push| D

    style A fill:#f9d71c,stroke:#333,stroke-width:2px
    style C fill:#8da0cb,stroke:#333,stroke-width:2px
    style F fill:#66c2a5,stroke:#333,stroke-width:2px

Now, let's walk through each step to get your site live.

Setup

1. Scaffolding a Zola project

First, let's create a new Zola project:

nix shell nixpkgs#zola -c zola init my-zola-site
cd my-zola-site

This command creates a new Zola project named my-zola-site. The Zola CLI will ask you some setup questions. Don't worry too much about your choices; you can always change them later in config.toml.

After setup, your project structure should look like this:

.
├── config.toml
├── content
├── static
├── templates
└── themes

To see your site locally, run:

nix shell nixpkgs#zola -c zola serve

Visit the URL printed in your terminal (usually http://127.0.0.1:1111) to see your new Zola site:

img

By default Zola will serve on http://127.0.0.1:1111, but you can change the interface and port with the --interface and --port flags respectively.

2. Setting up a Nix Flake

Create a file named flake.nix in your project root with the following content:

flake.nix
1{
2 description = "Zola site built with Nix";
3
4 inputs = {
5 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6 flake-utils.url = "github:numtide/flake-utils";
7 };
8
9 outputs = { self, nixpkgs, flake-utils }:
10 flake-utils.lib.eachDefaultSystem (system:
11 let
12 pkgs = nixpkgs.legacyPackages.${system};
13 in
14 {
15 devShells.default = pkgs.mkShell {
16 buildInputs = [ pkgs.zola ];
17 };
18
19 packages.default = pkgs.stdenv.mkDerivation {
20 name = "example"; # replace me
21 src = self;
22 buildInputs = [ pkgs.zola ];
23 buildPhase = "zola build";
24 installPhase = "cp -r public $out";
25 };
26 }
27 );
28}

This flake defines both a development environment and a build process for your Zola site.

Detailed Flake Summary

Let's break down the key parts of this Nix flake:

  1. Description: A brief description of the flake's purpose.
  2. Inputs:
    • nixpkgs: The main Nix packages repository.
    • flake-utils: A utility library for writing flakes.
  3. Outputs: This function defines what the flake produces.
    • It uses flake-utils to generate outputs for each default system.
    • devShells.default: Defines a development environment with Zola installed.
    • packages.default: Defines how to build the Zola site:
      • Uses the flake's own directory as the source.
      • Builds the site with zola build.
      • Copies the public directory to the output.

This setup allows for consistent development and build environments across different machines.

To use the development environment:

nix develop

You should see that you now enter a bash environment. Now run:

zola serve

If this is successful, you will see the same output as we had above and should be able to navigate to the default Zola page.

To build the site:

nix build

3. GitHub Actions

Create a file at .github/workflows/publish.yml with the following content:

.github/workflows/publish.yml
1name: Publish
2
3on:
4 push:
5 branches: [main]
6 workflow_dispatch:
7
8permissions:
9 contents: read
10 pages: write
11 id-token: write
12 deployments: write
13
14jobs:
15 build:
16 runs-on: ubuntu-latest
17 steps:
18 - name: Checkout
19 uses: actions/checkout@main
20 with:
21 submodules: recursive
22 - name: Install Nix
23 uses: DeterminateSystems/nix-installer-action@main
24 - name: Run the Magic Nix Cache
25 uses: DeterminateSystems/magic-nix-cache-action@main
26 - name: Build with Nix
27 run: |
28 nix build '.?submodules=1#'
29 - name: Upload artifact
30 uses: actions/upload-pages-artifact@main
31 with:
32 path: ./result
33
34 deploy-production:
35 environment:
36 name: github-pages
37 url: ${{ steps.deployment.outputs.page_url }}
38 runs-on: ubuntu-latest
39 needs: build
40 if: github.ref == 'refs/heads/main'
41 steps:
42 - name: Deploy to GitHub Pages
43 id: deployment
44 uses: actions/deploy-pages@main

This workflow builds your site using Nix and deploys it to GitHub Pages whenever you push to the main branch.

Detailed GitHub Actions Summary

Let's break down the key components of this GitHub Actions workflow:

  1. Triggers: The workflow runs on pushes to the main branch and can be manually triggered.
  2. Permissions: Sets necessary permissions for GitHub Pages deployment.
  3. Jobs:
    • build:
      • Checks out the repository with submodules (important for themes).
      • Installs Nix using a third-party action.
      • Builds the site using our Nix configuration.
      • Uploads the built site as an artifact.
    • deploy:
      • Runs only after the build job succeeds.
      • Deploys the built site to GitHub Pages.

This workflow automates the entire process from pushing changes to your repository to having those changes live on your site.

Note the submodules: recursive parameter in the checkout step and also the flag '.?submodules=1#' passed in nix build. This is crucial if you're using a Zola theme as a Git submodule, ensuring it's properly included in the build.

4. GitHub Pages

In your GitHub repository settings, under "Pages", set the source to "GitHub Actions".

img

Deployment

To deploy your site:

  1. Commit your changes
  2. Push to your GitHub repository
  3. GitHub Actions will automatically build and deploy your site

You can monitor the deployment in the "Actions" tab of your GitHub repository.

Customization

To customize your Zola site:

  1. Theme: Choose a theme from the Zola themes gallery
  2. Configuration: Edit config.toml for site-wide settings
  3. Content: Add Markdown files to the content directory
  4. Templates: Customize HTML structure in the templates directory
  5. Static Files: Add images, CSS, or JavaScript to the static directory

Always test changes locally with zola serve before pushing to GitHub.

Conclusion

You now have a Zola site that automatically builds and deploys to GitHub Pages using Nix and GitHub Actions. This setup provides reproducible builds, automated deployments, and free hosting.

The source code for this site can serve as a reference for your own projects.

Further Reading