Home

Building Raspberry Pi SD images declaratively with NixOS

· 2 min read·Linux·Raspberry pi

One flake, one command, one bootable image per board: how I replaced hand-configured Raspberry Pi OS installs with nixos-generators.

Every Raspberry Pi in the house used to be a snowflake: the same base image, then an hour of apt, ssh keys and config edits that nobody wrote down. After moving my laptop to NixOS the obvious next step was to build the Pi images the same way.

The flake

The whole thing is a flake with one output per board. nixos-generators does the heavy lifting and produces a compressed SD image.

{
  description = "Raspberry Pi images";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
    nixos-generators = {
      url = "github:nix-community/nixos-generators";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, nixos-generators, ... }: {
    packages.aarch64-linux.pi-01 = nixos-generators.nixosGenerate {
      system = "aarch64-linux";
      format = "sd-aarch64";
      modules = [ ./hosts/pi-01.nix ];
    };
  };
}

The host module is deliberately small. Anything shared between boards lives in a common module that each host imports.

{ config, pkgs, ... }:
{
  imports = [ ../modules/common.nix ];

  networking.hostName = "pi-01";
  services.openssh.enable = true;

  users.users.nei = {
    isNormalUser = true;
    extraGroups = [ "wheel" ];
    openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAA... nei@laptop" ];
  };

  system.stateVersion = "25.05";
}

Building on an x86 laptop

The images are aarch64 but the laptop is x86. Enabling binfmt emulation in the laptop configuration lets Nix build them locally, slowly but without any extra machine.

boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
A full image build under emulation takes about forty minutes on a laptop. A remote aarch64 builder or a cache of the kernel packages brings that down to a few minutes.
nix build .#pi-01
zstd -d result/sd-image/*.img.zst -o pi-01.img
sudo dd if=pi-01.img of=/dev/sdX bs=4M status=progress conv=fsync

Trade-offs

What got better

  • Reinstalling a board is one command and a card swap.
  • Every change is a commit, so a broken board is a git revert away from working.
  • Boards no longer drift apart over time.

What got worse

  • The first build is slow and the closure is large.
  • Debugging the boot process means learning the NixOS SD image layout.
  • Secrets need a real solution, see the checklist below.

Checklist

  • Build the image on the laptop with binfmt emulation
  • Boot it on a Pi 4 and log in over ssh
  • Switch pi-02 and pi-03 to generated images as well
  • Move ssh host keys and wifi passwords to sops-nix

The repository layout and the common module are described in the nixos-generators README, which is also where the list of supported formats lives.

Comments 0

No comments yet.

Sign in with GitHub to join the discussion.

Only your public profile is used.