NixOS on ARM/Building Images

From NixOS Wiki

Build your own image natively

You can customize image by using the following snippet.

# save as sd-image.nix somewhere
{ ... }: {
  imports = [
  # put your own configuration here, for example ssh keys:
  users.users.root.openssh.authorizedKeys.keys = [
     "ssh-ed25519 AAAAC3NzaC1lZDI1.... username@tld"

Then build with:

$ nix-build '<nixpkgs/nixos>' -A -I nixos-config=./sd-image.nix

Note that this requires a machine with aarch64. You can however also build it from your laptop using an aarch64 remote builder as described in Distributed build or ask for access on the community aarch64 builder.

if you use the experimental flake, instead of doing the above stuff, can put the following lines in flake.nix, git add flake.nix and build with nix build .#images.rpi2:

  description = "Build image";
  inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-22.11";
  outputs = { self, nixpkgs }: rec {
    nixosConfigurations.rpi2 = nixpkgs.lib.nixosSystem {
      modules = [
          nixpkgs.config.allowUnsupportedSystem = true;
          nixpkgs.hostPlatform.system = "armv7l-linux";
          nixpkgs.buildPlatform.system = "x86_64-linux"; #If you build on x86 other wise changes this.
          # ... extra configs as above
    images.rpi2 =;


It is possible to cross-compile from a different architecture. To cross-compile to armv7l, on the same sd-image.nix add in crossSystem:

{ ... }: {
  nixpkgs.crossSystem.system = "armv7l-linux";
  imports = [
  # ...

Compiling through binfmt QEMU

It is also possible to compile for aarch64 on your non-aarch64 local machine, or a remote builder, by registering QEMU as a binfmt wrapper for the aarch64 architecture. This wrapper uses emulation and will therefore be slower than comparable native machines or cross-compiling.

To enable the binfmt wrapper on NixOS, add the following to configuration.nix

  boot.binfmt.emulatedSystems = [ "aarch64-linux" ];

Then, add --argstr system aarch64-linux to the build command:

$ nix-build '<nixpkgs/nixos>' -A -I nixos-config=./sd-image.nix --argstr system aarch64-linux

If you are building on non-NixOS machine with QEMU binfmt wrapper configured, you will want to configure nix daemon to let it know that it can build for aarch64. Add the following line to /etc/nix/nix.conf: extra-platforms = aarch64-linux arm-linux

Note: archlinux users can install extra/qemu-system-aarch64, extra/qemu-user-static and extra/qemu-user-static-binfmt and restart systemd-binfmt.service. Check if binfmt is loaded by ls /proc/sys/fs/binfmt_misc/ (there must be qemu-aarch64 or needed architecture) and add line extra-sandbox-paths = /usr/bin/qemu-aarch64-static to /etc/nix/nix.conf and don't forget to restart the nix-daemon.service systemd unit afterwards.

If you want to build just one specific package, use this:

nix-build '<nixpkgs/nixos>' -A pkgs.theRequiredPackage --argstr system aarch64-linux -I nixos-config=/path/to/target/machine/nixos/config/copy

(the last option should not be required on NixOS machines)

Compiling through QEMU/kvm

It is also possible to build nixos images through full emulation using QEMU/kvm but will be way slower than native and binfmt QEMU.

Alternatives to building custom images

Stock NixOS installer image with custom U-Boot

The Mic92/nixos-aarch64-images repository provides a mechanism to modify the official NixOS installer to embed the board-specific U-Boot firmware required for different boards. This method does not require QEMU or native ARM builds since the existing Hydra-built U-Boot binaries are used.

Editing the image manually

For some simple operations, like adding an SSH public key, the expected usage for new users is to manually edit the image, add the proper directory and authorized_keys file, with proper modes.

$ namei -l /home/nixos/.ssh/authorized_keys
f: /home/nixos/.ssh/authorized_keys
drwxr-xr-x root   root  /
drwxr-xr-x root   root  home
drwx------ nixos  users nixos
drwx------ nixos  users .ssh
-rw------- nixos  users authorized_keys