Installing NixOS on a Raspberry Pi 3

citizen428 profile image Michael Kohl Originally published at citizen428.net on ・3 min read

The process of installing NixOS on a Raspberry Pi 3 is pretty straightforward, as they are fully supported upstream. However, the documentation is somewhat spread out and occasionally a bit outdated and/or confusing, so I thought it may be worthwhile to summarize my recent experience.

  • Download an image from Hydra, NixOS' CI tool. For the Pi 3 you'll use an AArch 64 image of the latest release (currently 20.03), which can be found here.

  • Flash the image on an SD card with a tool of your choice, e.g. Etcher or dd. If you don't have an HDMI cable available you'll also have to edit/extlinux/extlinux.conf to configure the UART console. I had such a cable available and this post assumes you do to.

  • The first type you boot from this card the NixOS installer will expand the volume, which can take a little bit of time.

  • Once the system booted, it's time to get a basic configuration set up. I started from zupo's config, who wrote one of the first comprehensive tutorials for NixPS on Raspberry Pi.

  $ curl https://raw.githubusercontent.com/zupo/nix/master/rpi.nix > /etc/nixos/configuration.nix

There were two changes I needed to make: since NixOS 19.09 the first volume no longer holds /boot but only the Raspberry Pi firmware files, so it no longers needs to be resized. Also the configuration option determining whether or not documentation will be installed now has a different name. These are the changes I applied to /etc/nixos/configuration.nix:

    # File systems configuration for using the installer's partition layout
    fileSystems = {
  -    "/boot" = {
  -      device = "/dev/disk/by-label/NIXOS_BOOT";
  -      fsType = "vfat";
  -    };
      "/" = {
        device = "/dev/disk/by-label/NIXOS_SD";
        fsType = "ext4";
  @@ -31,17 +31,23 @@

    # Preserve space by sacrificing documentation and history
  -  services.nixosManual.enable = false;
  +  documentation.nixos.enable = false;
    nix.gc.automatic = true;

The file should now look like this:

  { config, pkgs, lib, ... }:
    # NixOS wants to enable GRUB by default
    boot.loader.grub.enable = false;

    # if you have a Raspberry Pi 2 or 3, pick this:
    boot.kernelPackages = pkgs.linuxPackages_latest;

    # A bunch of boot parameters needed for optimal runtime on RPi 3b+
    boot.kernelParams = ["cma=256M"];
    boot.loader.raspberryPi.enable = true;
    boot.loader.raspberryPi.version = 3;
    boot.loader.raspberryPi.uboot.enable = true;
    boot.loader.raspberryPi.firmwareConfig = ''
    environment.systemPackages = with pkgs; [

    # File systems configuration for using the installer's partition layout
      "/" = {
        device = "/dev/disk/by-label/NIXOS_SD";
        fsType = "ext4";

    # Preserve space by sacrificing documentation and history
    documentation.nixos.enable = false;
    nix.gc.automatic = true;
    nix.gc.options = "--delete-older-than 30d";
    boot.cleanTmpDir = true;

    # Configure basic SSH access
    services.openssh.enable = true;
    services.openssh.permitRootLogin = "yes";

    # Use 1GB of additional swap memory in order to not run out of memory
    # when installing lots of things while running other things at the same time.
    swapDevices = [ { device = "/swapfile"; size = 1024; } ];
  • Time to build from the new minimal configuration, do some cleanup work and reboot just in case:
  $ nixos-rebuild switch
  $ nix-collect-garbage -d
  $ nixos-rebuild switch # removes now unused boot loader entries
  $ reboot
  • Add a user account so we no longer need to SSH to the Pi as root. I opted for the declarative approach:
  users.users.pi = {
    isNormalUser = true;
    home = "/home/pi";
    extraGroups = [ "wheel" "networkmanager" ];
    openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... pi@other" ];

The extra groups allow the new user to execute commands as root via sudo and to configure the network. If you want to allow members of the wheel group to use sudo without a password, add the following option to your Nix configuration:

  security.sudo.wheelNeedsPassword = false;

With this new user in place we can also disable the permitRootLogin option in /etc/nixos/configuration.nix:

  - services.openssh.permitRootLogin = "yes";
  • Add some system packages. For basic necessities I prefer the declarative approach over installation with nix-env, e.g.:
  environment.systemPackages = [

That's it, have fun with NixOS on your Raspberry Pi 3.

Posted on by:

citizen428 profile

Michael Kohl


I dev @ DEV. Your friendly neighborhood anarcho-cynicalist. ¯\_(ツ)_/¯ and (╯°□°)╯︵ ┻━┻) are my two natural states. Tag mod for #ruby, #fsharp, #ocaml


markdown guide