Nixos-RaspberryPi

Unopinionated Nix flake for infrastructure, vendor packages, kernel, and some optimized third-party packages for NixOS running on Raspberry Pi devices.

Provides bootloader infrastructure

Manages Raspberry Pi firmware partition /boot/firmware (the path is configurable with boot.loader.raspberryPi.firmwarePath).

Partition provisioning is integrated with bootloader activation scripts, happening on NixOS generation switch, enabling to use deployment tools like nixos-anywhere without any interactive intervention.

Supported boot methods (configurable with boot.loader.raspberryPi.bootloader):

  • kernelboot (legacy), default for RPi5
  • uboot, default bootloader for all other boards
  • kernel, new generation of kernelboot, supporting multiple NixOS generations (see #60), default for RPi5 sd-image/installer images, recommended for new installations.

Provides vendor kernel packages with matched firmware

pkgs.linuxAndFirmware.default contains compatible:

  • linuxPackages_rpi<board model> # Linux kernel
  • raspberrypifw # Raspberry firmware, device trees (DTBs), device overlays
  • raspberrypiWirelessFirmware # wireless firmware

Latest stable version compatible with the board is selected in the flake module by default.

Provides 3rd-party optimised packages

overlays, containing vendor, and optimized packages, like libcamera, ffmpeg, etc.

Usage

Adding flake input

inputs = {
  # follow `main` branch of this repository, considered being stable
  nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main";
};
 
# Optional: Binary cache for the flake
nixConfig = {
  extra-substituters = [
    "https://nixos-raspberrypi.cachix.org"
  ];
  extra-trusted-public-keys = [
    "nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
  ];
};

Using the flake to create NixOS configuration

There’re helper functions intended to be used as a drop-in replacement for nixpkgs.lib.nixosSystem:

  • nixos-raspberrypi.lib.nixosSystem
  • nixos-raspberrypi.lib.nixosSystemFull - same as above, but with RPi-optimized overlays applied globally, this may lead to more rebuilds
  • nixos-raspberrypi.lib.nixosInstaller - same as nixosSystemFull but with additional installer-specific modules

All of them take the following additional optional arguments:

  • nixpkgs – default = nixpkgs of the nixos-raspberrypi will be used
  • trustCaches – default=true, trust binary caches of nixos-raspberrypi
nixosConfigurations.rpi5-demo = nixos-raspberrypi.lib.nixosSystem {
  specialArgs = inputs;
  modules = [
    {
      # Hardware specific configuration, see section below for a more complete
      # list of modules
      imports = with nixos-raspberrypi.nixosModules; [
        raspberry-pi-5.base
        raspberry-pi-5.page-size-16k
        raspberry-pi-5.display-vc4
        raspberry-pi-5.bluetooth
      ];
    }
 
    ({ config, pkgs, lib, ... }: {
      networking.hostName = "rpi5-demo";
 
      system.nixos.tags = let
        cfg = config.boot.loader.raspberryPi;
      in [
        "raspberry-pi-${cfg.variant}"
        cfg.bootloader
        config.boot.kernelPackages.kernel.version
      ];
    })
 
    # ...
 
  ];
};

See also: https://github.com/nvmd/nixos-raspberrypi-demo, Installers and examples.

Choosing modules corresponding to your hardware

See flake.nix, nixosModules for a full list of configuration modules for your hardware. Here is the list of the most important:

imports = with nixos-raspberrypi.nixosModules; [
  # Base board support modules
  raspberry-pi-02.base
  raspberry-pi-3.base
  raspberry-pi-4.base
  raspberry-pi-5.base
 
  # (Potentially) All boards
  usb-gadget-ethernet # Configures USB Gadget/Ethernet - Ethernet emulation over USB
 
  # RPi4:
  # import this if you have the display, on rpi4 this is the only display configuration option
  raspberry-pi-4.display-vc4
 
  # RPi5:
  raspberry-pi-5.page-size-16k  # Recommended: optimizations and fixes for issues arising from 16k memory page size (only for systems running default rpi5 (bcm2712) kernel)
  # use one of following for the "PrimaryGPU" configuration:
  raspberry-pi-5.display-vc4  # "regular" display connected
  raspberry-pi-5.display-rp1  # for RP1-connected (DPI/composite/MIPI DSI) display
];

Configure the bootloader and firmware (config.txt)

Sane default configuration is provided by the base module for a corresponding Raspberry board, but further configuration is, of course, possible:

Configuration options for the bootloader are in boot.loader.raspberryPi (defined in modules/system/boot/loader/raspberrypi/default.nix).

Raspberry’s config.txt can be configured with hardware.raspberry-pi.config options, see modules/configtxt.nix as an example (this is the default configuration as provided by RaspberryPi OS, but translated to nix format).

Options for advanced usage

Options for a more fine-grained control:

see implementation details in lib/default.nix, lib/internal.nix Use nixos-raspberrypi.lib.int.nixosSystemRPi instead of nixos-raspberrypi.lib.nixosSystem Use regular nixpkgs.lib.nixosSystem importing the modules manually, see below

imports = with nixos-raspberrypi.nixosModules; [
 
  # Required: Add necessary overlays with kernel, firmware, vendor packages
  nixos-raspberrypi.lib.inject-overlays
 
  # Binary cache with prebuilt packages for the currently locked `nixpkgs`,
  # see `devshells/nix-build-to-cachix.nix` for a list
  trusted-nix-caches
 
  # Optional: All RPi and RPi-optimised packages to be available in `pkgs.rpi`
  nixpkgs-rpi
 
  # Optonal: add overlays with optimised packages into the global scope
  # provides: ffmpeg_{4,6,7}, kodi, libcamera, vlc, etc.
  # This overlay may cause lots of rebuilds (however many
  #  packages should be available from the binary cache)
  nixos-raspberrypi.lib.inject-overlays-global
];

Installer configurations

The flake provides installation SD card images for Raspberry Pi Zero2, 3, 4, and 5, based on https://github.com/nix-community/nixos-images. They have several advantages over the “standard” ones, making the installation more user-friendly: mDNS enabled, iwd for easier wlan configuration, etc.

Note: these images are mutable, i.e. they’re suitable to be used both as an installation media, and as a ready to use system on the sd-card. The partition table will be expanded to use all the available space during the first boot. This can helpful for boards with a single storage device option, like RPi Zero/Zero 2.

Tip: installer images use new generational bootloader for RPi5 by default (see #60), to keep that in your configuration, set boot.loader.raspberryPi.bootloader = "kernel". This is recommended for new installations.

See nixosConfigurations.rpi{02,4,5}-installer in flake.nix.

SD image can be built with:

nix build .#installerImages.rpi02
nix build .#installerImages.rpi3
nix build .#installerImages.rpi4
nix build .#installerImages.rpi5

Randomly generated connection credentials will be displayed on the screen, once the system is booted.

Network access to Raspberry Pi Zero2 (RPi02) boards is also possible via USB Gadget/Ethernet functionality.

Tip: You can optionally replace # YOUR SSH PUB KEY HERE # in custom-user-config with your SSH public key to generate the image with your SSH key already baked in

.#nixosConfigurations.rpi{02,4,5}-installer.config.system.build.toplevel are included in the binary cache.

NixOS configuration examples

Sophisticated demo configurations are available in https://github.com/nvmd/nixos-raspberrypi-demo.

Installer configurations can also double as the configuration examples.

Deployment

for example, with nixos-anywhere to the system running installer image (will use disko to set the disks up):

nixos-anywhere --flake .#<system> root@<hostname>"

or, to an already running system (to change configuration of it):

nixos-rebuild switch --flake .#<system> --target-host root@<hostname>

Alternative ways to get individual packages

An alternative ways to consume individual packages without overlays are:

to get it directly from the flake, it will based on stable nixpkgs without any of other optimisations transitively applied (i.e. only this particular package is optimised):

  environment.systemPackages = [
    nixos-raspberrypi.packages.aarch64-linux.vlc
  ];

to get it from nixos-raspberrypi.legacyPackages.<system>. Here all overlays are applied.