Difference between revisions of "NixOS on ARM"

From NixOS Wiki
Jump to: navigation, search
(Adding 24.11 release to the image list.)
(Updated flake stable arm64 and mobile noxios suggetsions)
Line 1: Line 1:
ARM support for NixOS is a work-in-progress, but is progressing quickly.
+
## NixOS installation & configuration
  
The support varies depending on the architecture and the specific boards. The way the ARM integration is built into NixOS is by making generic builds the first-class citizens; as soon as there is upstream support for the board in the kernel and the bootloader, NixOS should work once updated to these versions. It is still possible, when needed, to build and use a customised bootloader and kernel for specific boards<sup>[[Talk:NixOS_on_ARM#NixOS_.22support.22_for_board-specific_kernels_or_bootloaders|[reference needed]]]</sup>. At this moment in time (late 2021) only AArch64 has full support upstream.
+
The installation image contains a MBR partition table with two partitions: a FAT16/32 `/boot` partition and an ext4 root filesystem. This design allows you to directly reuse the SD image's partition layout and "install" NixOS on the same storage device by replacing the default configuration and running `nixos-rebuild`. On first boot, the image automatically resizes the rootfs partition to utilize all available storage space.
  
Though, neither armv6l or armv7l are being ignored, fixes are worked on and approved as needed; what's missing is support and upstream builds being maintained in binary form. At the time of writing, no publicly available caches for armv6l or armv7l are available.<!-- please get in touch with samueldr on the NixOS on ARM channel if you want to share your own cache, before editing. We need to review the wording to make it crystal clear it's a user-provided cache. -->
+
NixOS on ARM supports two approaches to system configuration: traditional configuration.nix files and the now-standard Flakes approach (recommended since NixOS 25.05). Both methods are covered below.
  
'''For images links, including UEFI install''', skip to the [[NixOS on ARM#Installation|Installation]] section.
+
### Boot Process Overview
  
== Supported devices ==
+
All ARM boards in NixOS use U-Boot as the bootloader, alongside U-Boot's Generic Distro Configuration Concept to communicate boot information (kernel zImage path, initrd, DTB, command line arguments). U-Boot scans storage devices for `/extlinux/extlinux.conf` or `/boot/extlinux/extlinux.conf` files (generated by NixOS) and uses the bootable partition flag.
  
Table legend:
+
U-Boot provides both an interactive shell and generation selection menu (similar to GRUB). Board-specific input/display support varies - check your device's wiki page for details.
* SoC - https://en.wikipedia.org/wiki/System_on_a_chip
 
* ISA - https://en.wikipedia.org/wiki/Instruction_set_architecture
 
  
=== Upstream (NixOS) supported devices ===
+
### Basic Setup with configuration.nix
  
NixOS has support for these boards using AArch64 architecture on the nixpkgs-unstable and stable channel.
+
To generate a default `/etc/nixos/configuration.nix` file and detect hardware:
  
Support for those board assumes as much is supported as Mainline Linux supports.
+
```bash
<!--
+
sudo nixos-generate-config
Order for the device table is:
+
```
* By manufacturer name, alphabetical.
 
* By release date, chronological (older first).
 
-->
 
{|class="table"
 
!width="2%"| Manufacturer
 
!width="2%"| Board
 
!width="2%"| SoC
 
!width="1%"| ISA
 
!width="2%"| CPU
 
!width="1%"| RAM
 
!width="2%"| Storage
 
|-
 
| Raspberry Pi Foundation
 
| [[NixOS_on_ARM/Raspberry_Pi_3|Raspberry Pi 3]]
 
| Broadcom BCM2837
 
| AArch64 / ARMv7
 
| 4× Cortex-A53 @ 1.2 - 1.4 GHz
 
| 1 GB
 
| SD/microSD
 
|-
 
| Raspberry Pi Foundation
 
| [[NixOS_on_ARM/Raspberry_Pi 4|Raspberry Pi 4]]
 
| Broadcom BCM2711
 
| AArch64 / ARMv7
 
| 4× Cortex-A72 @ 1.5 - 1.8 GHz
 
| 1-8 GB
 
| microSD, eMMC
 
|}
 
=== Community supported devices ===
 
  
<!--
+
Here's a modern configuration template suitable for most ARM boards:
Order for the device table is:
 
* By manufacturer name, alphabetical.
 
* By release date, chronological (older first).
 
-->
 
<div class="table">
 
{|class="table"
 
!width="2%"| Manufacturer
 
!width="2%"| Board
 
!width="2%"| SoC
 
!width="1%"| ISA
 
!width="2%"| CPU
 
!width="2%"| RAM
 
!width="2%"| Storage
 
|-
 
| Apple
 
| [[NixOS_on_ARM/Apple Silicon Macs|Apple Silicon Macs]]
 
| M1/M1 Pro/M1 Max
 
| AArch64
 
| —
 
| —
 
| NVMe
 
|-
 
| ASUS
 
| [[NixOS_on_ARM/Tinker Board|Tinker Board]]
 
| Rockchip RK3288
 
| ARMv7
 
| 4× Cortex-A17
 
| 2 GB
 
| microSD
 
|-
 
| Banana Pi
 
| [[NixOS_on_ARM/Banana Pi|Banana Pi]]
 
| Allwinner A20
 
| ARMv7
 
| 2× Cortex-A7
 
| 1 GB
 
| SD, SATA
 
|-
 
| Banana Pi M64
 
| [[NixOS_on_ARM/Banana Pi M64|Banana Pi M64]]
 
| Allwinner A64
 
| ARMv8
 
| 4× Cortex-A53
 
| 2 GB
 
| microSD, 8GB eMMc
 
|-
 
| Banana Pi BPI-M5
 
| [[NixOS_on_ARM/Banana Pi BPI-M5|Banana Pi BPI-M5]]
 
| Amlogic S905X3
 
| ARMv8.2
 
| 4× Cortex-A55
 
| 4 GB LPDDR4
 
| microSD, 16G eMMC
 
|-
 
| BeagleBoard.org
 
| [[NixOS_on_ARM/BeagleBone_Black|BeagleBone Black]]
 
| TI AM335x [https://git.beagleboard.org/beagleboard/beaglebone-black (src)]
 
| ARMv7
 
| 1× Cortex-A8 @ 1 GHz
 
| 512 MB
 
| 4 GB eMMC, microSD
 
|-
 
| Firefly
 
| [[NixOS_on_ARM/Firefly_AIO-3399C|AIO-3399C]]
 
| Rockchip RK3399
 
| AArch64
 
| 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz
 
| 2/4 GB
 
| 8/16 GB eMMC, microSD
 
|-
 
| FriendlyElec
 
| [[NixOS_on_ARM/NanoPC-T4|NanoPC-T4]]
 
| Rockchip RK3399
 
| AArch64
 
| 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz
 
| 4 GB
 
| 16 GB eMMC, microSD, NVMe
 
|-
 
| FriendlyElec
 
| [[NixOS_on_ARM/NanoPi-M4|NanoPi-M4]]
 
| Rockchip RK3399
 
| AArch64
 
| 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz
 
| 4 GB
 
| optional eMMC, microSD
 
|-
 
| FriendlyElec
 
| [[NixOS_on_ARM/NanoPi-R6C|NanoPi-R6C]]
 
| Rockchip RK3588S
 
| AArch64
 
| 4× ARM Cortex-A76 @ 2.4 GHz, 4× Cortex-A55 @ 1.8 Ghz
 
| 4 GB / 8 GB
 
| optional eMMC, microSD, NVMe
 
|-
 
| Hardkernel
 
| [[NixOS_on_ARM/ODROID-HC1|ODROID-HC1 & ODROID-HC2]]
 
| Samsung Exynos 5422
 
| ARMv7
 
| 4× Cortex-A15 @ 2GHz, 4× Cortex-A7 @ 1.4GHz
 
| 2 GB
 
| microSD
 
|-
 
| Hardkernel
 
| [[NixOS_on_ARM/ODROID-C2|ODROID-C2]]
 
| Amlogic S905
 
| AArch64
 
| 4× Cortex-A53 @ 1.5GHz
 
| 2 GB
 
| eMMC, microSD
 
|-
 
| Hardkernel
 
| [[NixOS_on_ARM/ODROID-HC4|ODROID-HC4]]
 
| Amlogic S905X3
 
| AArch64
 
| 4× Cortex-A55 @ 1.8GHz
 
| 4 GB
 
| microSD, SATA
 
|-
 
| Libre Computer
 
| [[NixOS_on_ARM/Libre_Computer_ROC-RK3399-PC|ROC-RK3399-PC]]
 
| Rockchip RK3399
 
| AArch64
 
| 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz
 
| 4 GB
 
| eMMC, microSD, NVMe
 
|-
 
| Libre Computer
 
| [[NixOS_on_ARM/Libre_Computer_ROC-RK3328-CC|ROC-RK3328-CC]]
 
| Rockchip RK3328
 
| AArch64
 
| 4× ARM Cortex-A53 @ 1.4GHz
 
| 4 GB
 
| eMMC, microSD
 
|-
 
| Libre Computer
 
| [[NixOS_on_ARM/Libre_Computer_AML-S905X-CC-V2|AML-S905X-CC-V2]]
 
| Amlogic S905X
 
| AArch64
 
| 4× Cortex-A53 @ 1.512 GHz
 
| 1/2GB
 
| eMMC, microSD
 
|-
 
| Linksprite
 
| [[NixOS_on_ARM/PcDuino3_Nano|pcDuino3 Nano]]
 
| Allwinner A20
 
| ARMv7
 
| 2× Cortex-A7 @ 1 GHz
 
| 1 GB
 
| 4 GB NAND, microSD, SATA
 
|-
 
| NVIDIA
 
| [[NixOS_on_ARM/Jetson TK1|Jetson TK1]]
 
| Tegra K1/T124
 
| ARMv7
 
| 4× Cortex-A15 @ 2.3 GHz
 
| 2 GB
 
| 16 GB eMMC, SD, SATA
 
|-
 
| NXP
 
| [https://github.com/NiklasGollenstede/nixos-imx/ i.MX 8M Plus EVK]
 
| i.MX 8M Plus
 
| AArch64
 
| 4× Cortex-A53 @ 1.8 Ghz
 
| 6 GB
 
| 32 GB eMMC, microSD
 
|-
 
| NXP
 
| [https://github.com/gangaram-tii/nixos-imx8mq/ i.MX 8M Quad EVK]
 
| i.MX 8M Quad
 
| AArch64
 
| 4× Cortex-A53 @ 1.5 Ghz + 1x Cortex-M4
 
| 3 GB
 
| 16 GB eMMC, microSD
 
|-
 
| OLIMEX
 
| [[NixOS_on_ARM/OLIMEX_Teres-A64|Teres-A64]]
 
| AllWinner A64
 
| AArch64
 
| 4x Cortex-A53 @ 1152MHz
 
| 2GB
 
| 16 GB eMMC, microSD
 
|-
 
| Orange Pi
 
| [[NixOS_on_ARM/Orange_Pi_One|Orange Pi One]]
 
| Allwinner H3
 
| ARMv7
 
| 4× Cortex-A7 @ 1.2 GHz
 
| 512 MB
 
| microSD
 
|-
 
| Orange Pi
 
| [[NixOS_on_ARM/Orange_Pi_PC|Orange Pi PC]]
 
| Allwinner H3
 
| ARMv7
 
| 4× Cortex-A7 @ 1.6 GHz
 
| 1 GB
 
| SD/microSD
 
|-
 
| Orange Pi
 
| [[NixOS_on_ARM/Orange_Pi_Zero_Plus2_H5|Orange Pi Zero Plus2 (H5)]]
 
| Allwinner H5
 
| AArch64
 
| 4× Cortex-A53 @ 1.2 GHz
 
| 1 GB
 
| SD/microSD + 8GB eMMC
 
|-
 
| Orange Pi
 
| [[NixOS_on_ARM/Orange_Pi_Zero2_H626|Orange Pi Zero2 (H616)]]
 
| Allwinner H616
 
| AArch64
 
| 4× Cortex-A53 @ 1.2 GHz
 
| 1 GB
 
| SD/microSD + 2MB SPI Flash
 
|-
 
| Orange Pi
 
| [[NixOS_on_ARM/Orange_Pi_R1_Plus_LTS|Orange Pi R1 Plus LTS]]
 
| Rockchip RK3328
 
| AArch64
 
| 4x Cortex-A53 @ -1.5 GHz
 
| 1 GB
 
| microSD
 
|-
 
| Orange Pi
 
| [[NixOS_on_ARM/Orange_Pi_5|Orange Pi 5]]
 
| Rockchip RK3588s
 
| AArch64
 
| 4× Cortex-A76 @ 2.4GHz, 4×Cortex-A55 @ 1.8 GHz
 
| 4/8/16 GB
 
| microSD, NVMe
 
|-
 
| Orange Pi
 
| [[NixOS_on_ARM/Orange_Pi_5_Plus|Orange Pi 5 Plus]]
 
| Rockchip RK3588
 
| AArch64
 
| 4× Cortex-A76 @ 2.4GHz, 4×Cortex-A55 @ 1.8 GHz
 
| 4/8/16 GB
 
| eMMC, microSD, NVMe
 
|-
 
| PINE64
 
| [[NixOS_on_ARM/PINE A64-LTS|PINE A64-LTS]]
 
| Allwinner R18
 
| AArch64
 
| 4× Cortex-A53 @ ? GHz
 
| 2 GB
 
| microSD & eMMC
 
|-
 
| PINE64
 
| [[NixOS_on_ARM/PINE64_Pinebook|Pinebook]]
 
| Allwinner A64
 
| AArch64
 
| 4× Cortex-A53 @ ? Ghz
 
| 2 GB
 
| microSD & eMMC
 
|-
 
| PINE64
 
| [[NixOS_on_ARM/PINE64_Pinebook_Pro|Pinebook Pro]]
 
| Rockchip RK3399
 
| AArch64
 
| 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz
 
| 4 GB
 
| microSD & eMMC
 
|-
 
| PINE64
 
| [[NixOS_on_ARM/PINE64_ROCK64|ROCK64]]
 
| Rockchip RK3328
 
| AArch64
 
| 4× Cortex-A53 @ 1.5 GHz
 
| 1/2/4 GB
 
| microSD/eMMC
 
|-
 
| PINE64
 
| [[NixOS_on_ARM/PINE64_ROCKPro64|ROCKPro64]]
 
| Rockchip RK3399
 
| AArch64
 
| 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz
 
| 2/4 GB
 
| microSD/eMMC
 
|-
 
| Clockworkpi
 
| [[NixOS_on_ARM/Clockworkpi_A06_uConsole|uConsole A06]]
 
| Rockchip RK3399
 
| AArch64
 
| 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz
 
| 4 GB
 
| microSD
 
|-
 
| Radxa
 
| [[NixOS on ARM/Radxa ROCK5 Model B|ROCK5 Model B]]
 
| Rockchip RK3588
 
| AArch64
 
| 4× Cortex-A76 @ 2.4GHz, 4×Cortex-A55 @ 1.8 GHz
 
| 4/8/16 GB
 
| eMMC, microSD, NVMe
 
|-
 
| Radxa
 
| [[NixOS on ARM/Radxa ROCK5 Model A|ROCK5 Model A]]
 
| Rockchip RK3588s
 
| AArch64
 
| 4× Cortex-A76 @ 2.4GHz, 4×Cortex-A55 @ 1.8 GHz
 
| 4/8/16 GB
 
| eMMC, microSD, NVMe
 
|-
 
| Raspberry Pi Foundation
 
| [[NixOS_on_ARM/Raspberry_Pi|Raspberry Pi]]
 
| Broadcom BCM2835
 
| ARMv6
 
| 1 × ARM1176 @ 700 MHz
 
| 256 MB / 512 MB
 
| SD/microSD
 
|-
 
| Raspberry Pi Foundation
 
| [[NixOS_on_ARM/Raspberry_Pi|Raspberry Pi 2]]
 
| Broadcom BCM2836
 
| ARMv7
 
| 4× Cortex-A7 @ 900 MHz
 
| 1 GB
 
| SD/microSD
 
|-
 
| Raspberry Pi Foundation
 
| [[NixOS_on_ARM/Raspberry_Pi 3|Raspberry Pi 3]]
 
| Broadcom BCM2837
 
| AArch64 / ARMv7
 
| 4× Cortex-A53 @ 1.2 GHz
 
| 1 GB
 
| SD/microSD
 
|-
 
| Raspberry Pi Foundation
 
| [[NixOS_on_ARM/Raspberry_Pi 4|Raspberry Pi 4]]
 
| Broadcom BCM2711
 
| AArch64 / ARMv7
 
| 4× Cortex-A53 @ 1.5 GHz
 
| 1-8 GB
 
| microSD
 
|-
 
| Raspberry Pi Foundation
 
| [[NixOS_on_ARM/Raspberry_Pi 5|Raspberry Pi 5]]
 
| Broadcom BCM2712
 
| AArch64
 
| 4× Cortex-A76 @ 2.4 GHz
 
| 4-16 GB
 
| microSD
 
|-
 
| Toshiba
 
| [[NixOS_on_ARM/Toshiba AC100|AC100 (mini laptop)]]
 
| Tegra 2 250 (T20)
 
| ARMv7
 
| 2× Cortex-A9 @ 1 GHz
 
| 512 MB
 
| 8­­–32 GB eMMC, SD
 
|-
 
| Wandboard
 
| [[NixOS_on_ARM/Wandboard|Wandboard Solo/Dual/Quad]]
 
| Freescale i.MX6
 
| ARMv7
 
| 1×/2×/4× Cortex-A9 @ 1000 MHz
 
| 512 MB / 1 GB / 2 GB
 
| microSD, SATA
 
|}
 
</div>
 
  
==== Special Devices ====
+
```nix
 +
{ config, pkgs, lib, ... }:
  
It is possible to emulate an ARM platform with QEMU.
+
{
 +
  # NixOS wants to enable GRUB by default
 +
  boot.loader.grub.enable = false;
 +
 
 +
  # Enables the generation of /boot/extlinux/extlinux.conf
 +
  boot.loader.generic-extlinux-compatible.enable = true;
 +
 +
  # Import hardware configuration generated by nixos-generate-config
 +
  # This should correctly set up your file systems
 +
  imports = [ ./hardware-configuration.nix ];
 +
 
 +
  # File systems configuration (if not correctly detected)
 +
  # Usually nixos-generate-config handles this properly,
 +
  # but this is provided as a fallback
 +
  /*
 +
  fileSystems = {
 +
    "/" = {
 +
      device = "/dev/disk/by-label/NIXOS_SD";
 +
      fsType = "ext4";
 +
    };
 +
  };
 +
  */
 +
 
 +
  # Adding a swap file is optional, but recommended for RAM-constrained devices
 +
  # Size is in MiB
 +
  # swapDevices = [ { device = "/swapfile"; size = 1024; } ];
 +
 
 +
  # Enable basic networking
 +
  networking.networkmanager.enable = true;
 +
 
 +
  # Basic firewall
 +
  networking.firewall.enable = true;
 +
 
 +
  # Set your time zone
 +
  time.timeZone = "UTC";
 +
 
 +
  # System state version - IMPORTANT: Do not change this after initial install
 +
  system.stateVersion = "25.05";
 +
}
 +
```
  
<div class="table-responsive">
+
Apply your configuration with:
{|class="table"
 
!width="2%"| Manufacturer
 
!width="2%"| Board
 
!width="2%"| SoC
 
!width="2%"| ISA
 
!width="2%"| CPU
 
!width="2%"| RAM
 
!width="2%"| Storage
 
|-
 
| QEMU
 
| [[NixOS_on_ARM/QEMU|QEMU]]
 
| —
 
| ARMv7
 
| up to 8
 
| up to 2 GB
 
| Anything QEMU supports
 
|}
 
</div>
 
  
== Installation ==
+
```bash
 +
sudo nixos-rebuild switch
 +
```
  
=== Getting the installer ===
+
### Kernel Selection
  
==== UEFI iso ====
+
Kernel selection depends on your specific ARM device:
  
{{note| On Raspberry Pi devices, the NixOS ISO are not compatible due to hardware limitations rather than issues with the NixOS installer itself. As a result, it is recommended to use the SD card images files (.img) instead for a successful installation experience.}}
+
- **For boards with good mainline support** (including Raspberry Pi 4/5 on aarch64):
 +
  ```nix
 +
  boot.kernelPackages = pkgs.linuxPackages_latest;
 +
  ```
  
Continue to the [[NixOS on ARM/UEFI|UEFI]] page.
+
- **For legacy Raspberry Pi models on armv6/armv7**:
 
+
  ```nix
==== SD card images (SBCs and similar platforms) ====
+
  boot.kernelPackages = pkgs.linuxPackages_rpi;
 
+
  ```
For <code>AArch64</code> it is possible to download images from Hydra.
 
 
 
* [https://hydra.nixos.org/job/nixos/release-24.11/nixos.sd_image.aarch64-linux 24.11]
 
* [https://hydra.nixos.org/job/nixos/release-24.05/nixos.sd_image.aarch64-linux 24.05]
 
* [https://hydra.nixos.org/job/nixos/release-23.11/nixos.sd_image.aarch64-linux 23.11]
 
* [https://hydra.nixos.org/job/nixos/trunk-combined/nixos.sd_image.aarch64-linux unstable (LTS kernel)]
 
* [https://hydra.nixos.org/job/nixos/trunk-combined/nixos.sd_image_new_kernel_no_zfs.aarch64-linux unstable (Latest kernel)]
 
 
 
On the page click on the latest successful build to get a download link under build products.
 
 
 
If the image has the extension <code>.zst</code>, it will need to be decompressed before writing to installation device. Use <code>nix-shell -p zstd --run "unzstd <img-name>.img.zst"</code> to decompress the image.
 
 
 
=== Installation steps ===
 
 
 
The .img files can be directly written to a microSD/SD card (minimal recommended size: 4 GB) using dd, once uncompressed from the ZSTD container. The SD card needs to be unmounted first.
 
 
 
Once the NixOS image file is downloaded, run the following command to install the image onto the SD Card, replace <code>/dev/mmcblk0</code> with the path to the SD card (use <code>dmesg</code> to find it out).
 
 
 
<code>
 
sudo dd if=nixos-sd-image-23.05pre482417.9c7cc804254-aarch64-linux.img of=/dev/mmcblk0 bs=10MB oflag=dsync status=progress
 
</code>
 
 
 
This should be enough to get you started, you may now boot your device for the first time.
 
 
 
The base images are configured to boot up with a serial TTY ( RX/TX UART ) @ 115200 Baud. That way you not necessarily have to have a HDMI Display and keyboard.
 
 
 
{{note| For some platforms, manually editing and adding kernel command-line arguments to <code>/boot/extlinux/extlinux.conf</code> may be needed for serial to work, and is "as" supported as would be editing the command-line manually during boot.}}
 
 
 
Continue with [[#NixOS installation & configuration]].
 
 
 
== Binary cache ==
 
 
 
=== AArch64 ===
 
 
 
The [https://hydra.nixos.org/ official NixOS Hydra] instance builds a full set of binaries (available on https://cache.nixos.org) for the AArch64 architecture on the nixpkgs-unstable and stable channels.
 
 
 
=== armv6l and armv7l ===
 
 
 
Some '''''users''''' have provided best effort caches for 32 bit ARM, but none are currently available.
 
 
 
== Build your own image natively ==
 
 
 
You can customize image by using the following snippet.
 
  
<syntaxHighlight lang=nix>
+
- **For boards requiring specialized kernels**:
# save as sd-image.nix somewhere
+
   Refer to the board-specific wiki page for recommended kernel packages.
{ ... }: {
 
   imports = [
 
    <nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix>
 
  ];
 
  # put your own configuration here, for example ssh keys:
 
  users.users.root.openssh.authorizedKeys.keys = [
 
    "ssh-ed25519 AAAAC3NzaC1lZDI1.... username@tld"
 
  ];
 
}
 
</syntaxHighlight>
 
  
Then build with:
+
### Modern Flakes-Based Approach (Recommended)
  
<syntaxHighlight lang=nix>
+
Since NixOS 25.05, Flakes are the standard recommended approach for system configuration. They provide reproducible builds, locked dependencies, and simplify cross-device management.
$ nix-build '<nixpkgs/nixos>' -A config.system.build.sdImage -I nixos-config=./sd-image.nix
 
</syntaxHighlight>
 
  
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 [https://github.com/nix-community/aarch64-build-box community aarch64 builder].
+
1. Create a `flake.nix` file:
  
if you use the experimental flake, instead of doing the above stuff, can put the following lines in <code>flake.nix</code>, <code>git add flake.nix</code> and build with <code>nix build .#images.rpi2</code>:
+
```nix
 
 
<syntaxHighlight lang=nix>
 
 
{
 
{
   description = "Build image";
+
   description = "NixOS configuration for my ARM device";
   inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-22.11";
+
 
   outputs = { self, nixpkgs }: rec {
+
   inputs = {
     nixosConfigurations.rpi2 = nixpkgs.lib.nixosSystem {
+
    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
 +
    nixos-hardware.url = "github:NixOS/nixos-hardware";
 +
  };
 +
 
 +
   outputs = { self, nixpkgs, nixos-hardware, ... }: {
 +
     nixosConfigurations.mydevice = nixpkgs.lib.nixosSystem {
 +
      system = "aarch64-linux"; # Or "armv6l-linux"/"armv7l-linux" for 32-bit ARM
 
       modules = [
 
       modules = [
         "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-raspberrypi.nix"
+
         # Hardware-specific modules (if available)
         {
+
        # nixos-hardware.nixosModules.raspberry-pi-4
          nixpkgs.config.allowUnsupportedSystem = true;
+
         # nixos-hardware.nixosModules.raspberry-pi-5
          nixpkgs.hostPlatform.system = "armv7l-linux";
+
       
          nixpkgs.buildPlatform.system = "x86_64-linux"; #If you build on x86 other wise changes this.
+
        # Your main configuration file
          # ... extra configs as above
+
        ./configuration.nix
        }
 
 
       ];
 
       ];
 
     };
 
     };
    images.rpi2 = nixosConfigurations.rpi2.config.system.build.sdImage;
 
 
   };
 
   };
 
}
 
}
</syntaxHighlight>
+
```
 +
 
 +
2. Apply your configuration with:
 +
 
 +
```bash
 +
sudo nixos-rebuild switch --flake .#mydevice
 +
```
 +
 
 +
The `#mydevice` part corresponds to the `nixosConfigurations.mydevice` entry in your flake.nix file.
  
=== Cross-compiling ===
+
### Binary Caches
  
It is possible to cross-compile from a different architecture. To cross-compile to <code>armv7l</code>, on the same <code>sd-image.nix</code> add in <code>crossSystem</code>:
+
#### AArch64 (ARM64)
 +
The official NixOS Hydra instance builds full binary sets for the AArch64 architecture, available on https://cache.nixos.org for both the nixpkgs-unstable and stable channels:
  
<syntaxHighlight lang=nix>
+
```nix
{ ... }: {
+
nix.settings = {
   nixpkgs.crossSystem.system = "armv7l-linux";
+
   substituters = [
   imports = [
+
    "https://cache.nixos.org"
     <nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix>
+
  ];
 +
   trusted-public-keys = [
 +
     "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
 
   ];
 
   ];
  # ...
+
};
}
+
```
</syntaxHighlight>
+
 
 +
#### armv6l and armv7l (32-bit ARM)
 +
There are currently no official binary caches for 32-bit ARM. Consider:
 +
- Building packages natively (slow on low-power devices)
 +
- Using cross-compilation (see below)
 +
- Setting up your own binary cache
  
=== Compiling through binfmt QEMU ===
+
For better performance on bandwidth-constrained devices, limit parallel connections:
  
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 <b>wrapper uses emulation</b> and will therefore be slower than comparable native machines or cross-compiling.
+
```nix
 +
nix.settings = {
 +
  max-substitution-jobs = 2;
 +
};
 +
```
  
To enable the binfmt wrapper on NixOS, add the following to <code>configuration.nix</code>
+
### Building on Resource-Constrained ARM Devices
  
<syntaxHighlight lang=nix>
+
ARM devices, especially older or low-power models, may struggle with building large packages. Consider these approaches:
{
 
  boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
 
}
 
</syntaxHighlight>
 
  
Then, add <code>--argstr system aarch64-linux</code> to the build command:
+
#### 1. Remote Builders
  
<syntaxHighlight lang=nix>
+
Configure a more powerful machine (ideally ARM64) as a remote builder:
$ nix-build '<nixpkgs/nixos>' -A config.system.build.sdImage -I nixos-config=./sd-image.nix --argstr system aarch64-linux
 
</syntaxHighlight>
 
  
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 <code>/etc/nix/nix.conf</code>:
+
```nix
<code>extra-platforms = aarch64-linux arm-linux</code>
+
nix.buildMachines = [{
{{note| archlinux users can install <code>extra/qemu-system-aarch64</code>, <code>extra/qemu-user-static</code> and <code>extra/qemu-user-static-binfmt</code>
+
  hostName = "builder";
and restart <code>systemd-binfmt.service</code>. Check if binfmt is loaded by <code>ls  /proc/sys/fs/binfmt_misc/</code> (there must be  <code>qemu-aarch64</code> or needed architecture) and add line <code><nowiki>extra-sandbox-paths = /usr/bin/qemu-aarch64-static</nowiki></code> to <code>/etc/nix/nix.conf</code> and don't forget to restart the <code>nix-daemon.service</code> systemd unit afterwards.}}
+
  system = "aarch64-linux";
 +
  maxJobs = 4;
 +
  speedFactor = 2;
 +
  supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
 +
}];
 +
nix.distributedBuilds = true;
 +
```
  
If you want to build just one specific package, use this:
+
For setup instructions, see the [Distributed Build](https://nixos.wiki/wiki/Distributed_build) wiki page.
<syntaxHighlight lang=nix>
 
nix-build '<nixpkgs/nixos>' -A pkgs.theRequiredPackage --argstr system aarch64-linux -I nixos-config=/path/to/target/machine/nixos/config/copy
 
</syntaxHighlight>
 
(the last option should not be required on NixOS machines)
 
  
=== Compiling through QEMU/kvm ===
+
#### 2. Cross-Compilation using QEMU with binfmt_misc
  
It is also possible to build nixos images through full emulation using QEMU/kvm but will be way slower than native and binfmt QEMU.
+
On an x86_64 NixOS system, enable ARM emulation:
  
== Installer image with custom U-Boot ==
+
```nix
 +
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
 +
```
  
The [https://github.com/Mic92/nixos-aarch64-images 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.
+
Then build ARM packages from your x86_64 machine using:
  
== Board-specific installation notes ==
+
```bash
 +
nix build --system aarch64-linux .#package
 +
```
  
Depending on the board, some additional preparation steps might be needed to make the SD card bootable on your device. All of the board-specific installation notes are now found on their respective pages.
+
Or for non-Flake commands:
  
== Enable UART ==
+
```bash
 +
nix-build '<nixpkgs>' -A pkgs.hello --argstr system aarch64-linux
 +
```
  
If you try to use UART to log on NixOS, you might hang on the line "Starting kernel ...". To enable UART, you will need to add at the end of the line that contains <code>loglevel4</code> in the file <code>/extlinux/extlinux.conf</code> the text:
+
#### 3. Building through QEMU/KVM
{{file|/extlinux/extlinux.conf||<nowiki>
 
    console=ttyAMA0,115200n8
 
</nowiki>}}
 
{{file|/extlinux/extlinux.conf||<nowiki>
 
    console=ttyS0,115200n8
 
</nowiki>}}
 
The actual device (<code>ttyAMA0</code>, <code>ttyS0</code>, <code>ttyS1</code>) will depend on the hardware.
 
  
== NixOS installation & configuration ==
+
While slower than other methods, full emulation through QEMU/KVM is possible for ARM development. See the [NixOS on ARM/QEMU](https://nixos.wiki/wiki/NixOS_on_ARM/QEMU) page for detailed setup.
  
{{outdated|The kernel version recommendations of this section are severely outdated. This section should be rewritten to be generic and refer people to the board-specific page. Only the board specific page should make recommendations about the kernel.}}
+
### Creating Custom ARM Images
  
The installation image is actually a MBR partition table plus two partitions; a FAT16 /boot and a ext4 root filesystem. The image is designed such that it's possible to directly reuse the SD image's partition layout and "install" NixOS on the very same SD card by simply replacing the default configuration.nix and running nixos-rebuild. Using this installation method is strongly recommended, though if you know exactly what you're doing and how U-Boot on your board works, you can use nixos-install as usual. To help with the SD card installation method, the boot scripts on the image automatically resize the rootfs partition to fit the SD card on the first boot.
+
#### Building with Flakes (Recommended)
  
* To generate a default <code>/etc/nixos/configuration.nix</code> file, run <code>sudo nixos-generate-config</code>.
+
Create a custom SD card image with a Flake:
  
* You can also use an existing template:
+
```nix
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
 
{ config, pkgs, lib, ... }:
 
 
{
 
{
   # NixOS wants to enable GRUB by default
+
   description = "Custom ARM image";
  boot.loader.grub.enable = false;
+
    
   # Enables the generation of /boot/extlinux/extlinux.conf
+
   inputs = {
   boot.loader.generic-extlinux-compatible.enable = true;
+
    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
+
   };
  # !!! If your board is a Raspberry Pi 1, select this:
+
    
  boot.kernelPackages = pkgs.linuxPackages_rpi;
+
   outputs = { self, nixpkgs }: {
  # On other boards, pick a different kernel, note that on most boards with good mainline support, default, latest and hardened should all work
+
     nixosConfigurations.armimage = nixpkgs.lib.nixosSystem {
  # Others might need a BSP kernel, which should be noted in their respective wiki entries
+
      system = "aarch64-linux"; # For building 64-bit ARM images
 
+
       modules = [
  # nixos-generate-config should normally set up file systems correctly
+
        # Base SD image module for your architecture
  imports = [ ./hardware-configuration.nix ];
+
        "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix"
   # If not, you can set them up manually as shown below
+
        # Your customizations
   /*
+
        ({ ... }: {
   fileSystems = {
+
          # Add your customizations here
    # Prior to 19.09, the boot partition was hosted on the smaller first partition
+
          users.users.root.openssh.authorizedKeys.keys = [
     # Starting with 19.09, the /boot folder is on the main bigger partition.
+
            "ssh-ed25519 AAAAC3NzaC1lZDI1.... username@tld"
    # The following is to be used only with older images. Note such old images should not be considered supported anymore whatsoever, but if you installed back then, this might be needed
+
          ];
    /*
+
        })
    "/boot" = {
+
       ];
       device = "/dev/disk/by-label/NIXOS_BOOT";
 
      fsType = "vfat";
 
    };
 
    */
 
    "/" = {
 
      device = "/dev/disk/by-label/NIXOS_SD";
 
       fsType = "ext4";
 
 
     };
 
     };
 +
   
 +
    # Make the SD image the default output
 +
    packages.aarch64-linux.default =
 +
      self.nixosConfigurations.armimage.config.system.build.sdImage;
 
   };
 
   };
  */
+
}
   
+
```
  # !!! Adding a swap file is optional, but recommended if you use RAM-intensive applications that might OOM otherwise.
 
  # Size is in MiB, set to whatever you want (though note a larger value will use more disk space).
 
  # swapDevices = [ { device = "/swapfile"; size = 1024; } ];
 
}</nowiki>}}
 
Note: the default configuration.nix will contain something like <code>imports = [ <nixos/modules/installer/sd-card/sd-image-armv7l-multiplatform.nix> ];</code> do not include that in your final installation or you will experience interesting problems. It is only for building the installation image!
 
  
==== First rebuild on ARMv6 and ARMv7 ====
+
Build with:
  
To rebuild your system, run: <code>sudo nixos-rebuild switch</code>
+
```bash
 +
nix build
 +
```
  
{{note|Instructions removed since they referred to a long abandoned user-provided cache...}}
+
#### Building the Traditional Way
<!--
 
To make the unsupported ARM experience slightly less painful, the config template adds <code>[...]</code> as a binary cache, which contains a small subset of packages on the unstable channel (though a caution for US users: the server hosting them is physically located in Finland). Note that the binary cache isn't enabled on the prebuilt images, so enable it via the command line when building for the first time:
 
  
<syntaxhighlight lang="bash">nixos-rebuild switch --fast --option binary-caches [...]/channel --option binary-cache-public-keys [...]-1:XXXXXXXXXXXXXX+XXXXXXXXXXXXXX=%</syntaxhighlight>
+
For non-Flake builds:
-->
 
  
== Details about the boot process ==
+
```bash
 +
nix-build '<nixpkgs/nixos>' -A config.system.build.sdImage -I nixos-config=./sd-image.nix
 +
```
  
On NixOS, all ARM boards are expected to use U-Boot as the firmware and bootloader. NixOS uses [https://github.com/u-boot/u-boot/blob/master/doc/develop/distro.rst U-Boot's Generic Distro Configuration Concept] as the mechanism to communicate boot information (such as path to kernel zImage, initrd, DTB, command line arguments). For a quick TL;DR about the generic distro configuration support: U-Boot is scripted to scan all attached storage devices & partitions and look for a file named <code>/extlinux/extlinux.conf</code> or <code>/boot/extlinux/extlinux.conf</code> (which will be generated by NixOS, just like <code>/boot/grub/grub.cfg</code> is generated on PCs). The partition needs to have its "bootable" flag set.
+
Where `sd-image.nix` contains:
  
U-Boot also provides an interactive shell and the generation selection menu (just like GRUB). However, support for input or display devices varies greatly, depending on the board. Details for what the boards support in relationship to the boot process are detailed in their respective pages.
+
```nix
 +
{ ... }: {
 +
  imports = [
 +
    <nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix>
 +
  ];
 +
 
 +
  # Your customizations here
 +
  users.users.root.openssh.authorizedKeys.keys = [
 +
    "ssh-ed25519 AAAAC3NzaC1lZDI1.... username@tld"
 +
  ];
 +
}
 +
```
  
== Porting NixOS to new boards ==
+
### U-Boot Customization
  
=== The easiest way ===
+
Some boards may require custom U-Boot builds. For boards supported by upstream U-Boot, you can cross-compile from an x86_64 host:
  
Assuming upstream U-Boot supports the board through a defconfig, it is possible possible to build U-Boot using the cross-compiling architecture from an x86_64 host. Here's a sample use.
+
```bash
 +
nix-shell -p 'let plat = pkgsCross.aarch64-multiplatform; in plat.buildUBoot{defconfig = "board_defconfig"; extraMeta.platforms = ["aarch64-linux"];}'
 +
```
  
<syntaxhighlight>
+
Replace `board_defconfig` with your board's U-Boot configuration name.
# Assuming you're in a recent nixpkgs checkout
 
$ nix-shell \
 
    -I "nixpkgs=$PWD" \
 
    -p 'let plat = pkgsCross.aarch64-multiplatform; in plat.buildUBoot{defconfig = "orangepi_zero_plus2_defconfig"; extraMeta.platforms = ["aarch64-linux"]; BL31 = "${plat.armTrustedFirmwareAllwinner}/bl31.bin"; filesToInstall = ["u-boot-sunxi-with-spl.bin"];}'
 
</syntaxhighlight>
 
  
For armv7 and armv6 <code>pkgsCross.arm-embedded</code> should work, this is available in the unstable channel (19.03 and following) by setting <code>-I "nixpkgs=/path/to/new-nixpkgs-checkout</code>.
+
For manual builds (when NixOS packages are unavailable):
  
This should build whatever is needed for, and then build U-Boot for the desired defconfig, then open a shell with the build in <code>$buildInputs</code>. Do note that this particular invocation may need more changes than only the defconfig if built for other than allwinner boards.
+
```bash
 +
nix-shell -E 'with import <nixpkgs> {}; stdenv.mkDerivation { name = "arm-shell"; buildInputs = [git gnumake gcc gcc-arm-embedded dtc bison flex python3 swig]; }'
 +
git clone git://git.denx.de/u-boot.git
 +
cd u-boot
 +
make CROSS_COMPILE=arm-none-eabi- board_defconfig
 +
make CROSS_COMPILE=arm-none-eabi-
 +
```
  
Here's an example command, for allwinner boards, on how to write to an SD card.
+
Flash the resulting U-Boot image to your storage device (SD card/eMMC/etc.) at the appropriate offset, typically:
  
<syntaxhighlight>
+
```bash
$ sudo dd if=$buildInputs/u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8
+
sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8
</syntaxhighlight>
+
```
  
=== The easy way ===
+
The seek value and filename vary by board - check your board's wiki page or documentation.
  
''(if you're lucky)''
+
### Optimizing Performance on ARM
  
If your board is an ARMv7 board supported by multi_v7_defconfig and you have access to U-Boot on the board, getting <code>sd-image-armv7l-linux.img</code> to boot is the easiest option:
+
For better performance on ARM devices:
  
* If you're lucky and your U-Boot build comes with the extlinux.conf support built in, the image boots out-of-the-box. This is the case for all (upstream) Allwinner and Tegra U-Boots, for instance.
+
```nix
* Otherwise, you can get the boot information (path to kernel zImage, initrd, DTB, command line arguments) by extracting <code>extlinux.conf</code> from the boot partition of the image, and then attempt to boot it via the U-Boot shell, or some other mechanism that your board's distro uses (e.g. <code>uEnv.txt</code>).
+
{
 +
  # CPU frequency scaling (if supported by your hardware)
 +
  powerManagement.cpuFreqGovernor = "ondemand";
 +
 
 +
  # IO scheduler tuning (improves SD card performance)
 +
  services.udev.extraRules = ''
 +
    # Set deadline scheduler for SD cards
 +
    ACTION=="add|change", KERNEL=="mmcblk[0-9]", ATTR{queue/scheduler}="mq-deadline"
 +
  '';
 +
 
 +
  # Zram swap (better than SD card swap)
 +
  zramSwap = {
 +
    enable = true;
 +
    algorithm = "zstd";
 +
  };
 +
 
 +
  # Using tmpfs for temp directories
 +
  boot.tmpOnTmpfs = true;
 +
}
 +
```
  
==== Building U-Boot from your NixOS PC ====
+
### Security Hardening for ARM Devices
  
Assuming
+
Since NixOS 25.05, additional security features are available that are relevant for ARM devices:
  
* Your board is supported upstream by U-Boot or there is a recent enough fork with <code>extlinux.conf</code> support.
+
```nix
* You do not have nix setup on an ARM device
+
{
* Your nix isn't setup for cross-compilation
+
  # Kernel hardening options
 +
  boot.kernelParams = [ "slab_nomerge" "init_on_alloc=1" "init_on_free=1" ];
 +
  boot.kernel.sysctl = {
 +
    "kernel.kptr_restrict" = 2;
 +
    "kernel.dmesg_restrict" = 1;
 +
  };
 +
 
 +
  # Mandatory Access Control (if supported by your hardware)
 +
  security.apparmor.enable = true;  # Less resource-intensive than SELinux
 +
 
 +
  # Memory protection
 +
  security.protectKernelImage = true;
 +
}
 +
```
  
It is still possible to build U-Boot using tools provided by NixOS.
+
Note: Always understand the security implications and compatibility impact of hardening options before applying them. Some settings may affect hardware compatibility or performance on specific ARM devices.
  
In the following terminal session, replace <code>orangepi_pc_defconfig</code> with the appropriate board [http://git.denx.de/?p=u-boot.git;a=tree;f=configs;hb=HEAD from the configs folder] of U-Boot.
+
### Wayland Support on ARM64
  
{{Commands|<nowiki>
+
Recent NixOS releases provide good Wayland support on ARM64 devices:
$ nix-shell -E 'with import <nixpkgs> {}; stdenv.mkDerivation { name = "arm-shell"; buildInputs = [git gnumake gcc gcc-arm-embedded dtc]; }'
 
$ git clone git://git.denx.de/u-boot.git
 
$ cd u-boot
 
# We're checking out a version from before the use of `binman`.
 
# The dtc package is 1.4.2, which does not include `pylibftd`.
 
# Furthermore, I do not know how to package the library so it would be
 
# available in the python interpreter, making binman happy.
 
$ git checkout v2017.03
 
$ make -j4 CROSS_COMPILE=arm-none-eabi- orangepi_pc_defconfig
 
$ make -j4 CROSS_COMPILE=arm-none-eabi-
 
</nowiki>}}
 
  
The name of the final file will change depending on the board. For this specific build, and most Allwinner builds, the file will be named <code>u-boot-sunxi-with-spl.bin</code>.
+
```nix
 
+
{
You can flash this file to boot device with
+
  # For GNOME
 
+
  services.xserver = {
{{Commands|<nowiki>
+
    enable = true;
dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8
+
    displayManager.gdm.enable = true;
</nowiki>}}
+
    desktopManager.gnome.enable = true;
 +
    displayManager.gdm.wayland = true; # Explicitly enable Wayland
 +
  };
 +
 
 +
  # For KDE Plasma
 +
  services.xserver = {
 +
    enable = true;
 +
    displayManager.sddm.enable = true;
 +
    desktopManager.plasma5.enable = true;
 +
    displayManager.defaultSession = "plasmawayland";
 +
  };
 +
 
 +
  # Required for GPU acceleration
 +
  hardware.opengl = {
 +
    enable = true;
 +
    driSupport = true;
 +
  };
 +
}
 +
```
  
Note: This mailing list contains a patch which may help some builds: https://lists.denx.de/pipermail/u-boot/2016-December/275664.html
+
For Raspberry Pi 5, add `dtoverlay=vc4-kms-v3d-pi5` in `/boot/config.txt` to enable GPU drivers compatible with Wayland.
  
=== The hard way ===
+
### Common ARM Device Troubleshooting
  
Alternatively/if all else fails, you can do it the hard way and bootstrap NixOS from an existing ARM Linux installation.
+
1. **UART Console Access**: If your device isn't booting properly, enable UART:
 +
  ```nix
 +
  boot.kernelParams = [
 +
    "console=ttyS0,115200n8"  # Adjust ttyS0 to match your device's UART
 +
  ];
 +
  ```
  
=== Contributing new boards to nixpkgs ===
+
  The actual device (ttyAMA0, ttyS0, ttyS1) depends on your hardware. See the [Enable UART](https://nixos.wiki/wiki/NixOS_on_ARM#Enable_UART) section for details.
  
* Add a new derivation for your board's U-Boot configuration, see for example ubootPine64LTS in {{Nixpkgs Link|short=all-packages.nix|pkgs/top-level/all-packages.nix}}.
+
2. **Memory Constraints**: For devices with limited RAM:
* If your board's U-Boot configuration doesn't use the <code>extlinux.conf</code> format by default, create a patch to enable it. Some C hacking skills & U-Boot knowledge might be required. For some pointers, see this patch to enable it on the Versatile Express.
+
  ```nix
* Make a pull request, also containing the board-specific instructions.
+
  nix.settings.cores = 1; # Limit parallel builds
 +
  nix.settings.max-jobs = 1;
 +
  boot.tmp.cleanOnBoot = true; # Clean /tmp on boot
 +
  ```
  
== Support ==
+
3. **Network Issues**: For better wireless support:
 +
  ```nix
 +
  networking.networkmanager.enable = true;
 +
  hardware.enableRedistributableFirmware = true; # For WiFi firmware
 +
  ```
  
Only AArch64 is supported by NixOS.
+
### Related Projects
  
All 32 bit ARM platforms are experimental for the time being.
+
#### NixOS Mobile
  
There is a dedicated room for the upstream effort on Matrix,
+
For mobile devices like smartphones and tablets, check out the [Mobile NixOS project](https://github.com/mobile-nixos/mobile-nixos). This project extends NixOS to run on devices like the PinePhone and select OnePlus models, with features specifically designed for mobile use cases.
[https://matrix.to/#/#nixos-on-arm:nixos.org #nixos-on-arm:nixos.org].
 
  
== Resources ==
+
Mobile NixOS provides specialized modules for:
 +
- Touch input and mobile-friendly UI
 +
- Power management
 +
- Cellular modem support
 +
- Mobile hardware integration
  
=== Subpages ===
+
Visit the [Mobile NixOS documentation](https://mobile.nixos.org/) for detailed setup and configuration guidance.
  
The following is a list of all sub-pages of the ''NixOS on ARM'' topic.
+
#### QEMU Emulation
  
{{Special:PrefixIndex/{{FULLPAGENAME}}/ |hideredirects=1 |stripprefix=1}}
+
For detailed instructions on running NixOS ARM in QEMU, see the dedicated [NixOS on ARM/QEMU](https://nixos.wiki/wiki/NixOS_on_ARM/QEMU) wiki page.

Revision as of 10:06, 2 April 2025

    1. NixOS installation & configuration

The installation image contains a MBR partition table with two partitions: a FAT16/32 `/boot` partition and an ext4 root filesystem. This design allows you to directly reuse the SD image's partition layout and "install" NixOS on the same storage device by replacing the default configuration and running `nixos-rebuild`. On first boot, the image automatically resizes the rootfs partition to utilize all available storage space.

NixOS on ARM supports two approaches to system configuration: traditional configuration.nix files and the now-standard Flakes approach (recommended since NixOS 25.05). Both methods are covered below.

      1. Boot Process Overview

All ARM boards in NixOS use U-Boot as the bootloader, alongside U-Boot's Generic Distro Configuration Concept to communicate boot information (kernel zImage path, initrd, DTB, command line arguments). U-Boot scans storage devices for `/extlinux/extlinux.conf` or `/boot/extlinux/extlinux.conf` files (generated by NixOS) and uses the bootable partition flag.

U-Boot provides both an interactive shell and generation selection menu (similar to GRUB). Board-specific input/display support varies - check your device's wiki page for details.

      1. Basic Setup with configuration.nix

To generate a default `/etc/nixos/configuration.nix` file and detect hardware:

```bash sudo nixos-generate-config ```

Here's a modern configuration template suitable for most ARM boards:

```nix { config, pkgs, lib, ... }:

{

 # NixOS wants to enable GRUB by default
 boot.loader.grub.enable = false;
 
 # Enables the generation of /boot/extlinux/extlinux.conf
 boot.loader.generic-extlinux-compatible.enable = true;

 # Import hardware configuration generated by nixos-generate-config
 # This should correctly set up your file systems
 imports = [ ./hardware-configuration.nix ];
 
 # File systems configuration (if not correctly detected)
 # Usually nixos-generate-config handles this properly,
 # but this is provided as a fallback
 /*
 fileSystems = {
   "/" = {
     device = "/dev/disk/by-label/NIXOS_SD";
     fsType = "ext4";
   };
 };
 */
 
 # Adding a swap file is optional, but recommended for RAM-constrained devices
 # Size is in MiB
 # swapDevices = [ { device = "/swapfile"; size = 1024; } ];
 
 # Enable basic networking
 networking.networkmanager.enable = true;
 
 # Basic firewall
 networking.firewall.enable = true;
 
 # Set your time zone
 time.timeZone = "UTC";
 
 # System state version - IMPORTANT: Do not change this after initial install
 system.stateVersion = "25.05";

} ```

Apply your configuration with:

```bash sudo nixos-rebuild switch ```

      1. Kernel Selection

Kernel selection depends on your specific ARM device:

- **For boards with good mainline support** (including Raspberry Pi 4/5 on aarch64):

 ```nix
 boot.kernelPackages = pkgs.linuxPackages_latest;
 ```

- **For legacy Raspberry Pi models on armv6/armv7**:

 ```nix
 boot.kernelPackages = pkgs.linuxPackages_rpi;
 ```

- **For boards requiring specialized kernels**:

 Refer to the board-specific wiki page for recommended kernel packages.
      1. Modern Flakes-Based Approach (Recommended)

Since NixOS 25.05, Flakes are the standard recommended approach for system configuration. They provide reproducible builds, locked dependencies, and simplify cross-device management.

1. Create a `flake.nix` file:

```nix {

 description = "NixOS configuration for my ARM device";
 
 inputs = {
   nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
   nixos-hardware.url = "github:NixOS/nixos-hardware";
 };
 
 outputs = { self, nixpkgs, nixos-hardware, ... }: {
   nixosConfigurations.mydevice = nixpkgs.lib.nixosSystem {
     system = "aarch64-linux"; # Or "armv6l-linux"/"armv7l-linux" for 32-bit ARM
     modules = [
       # Hardware-specific modules (if available)
       # nixos-hardware.nixosModules.raspberry-pi-4
       # nixos-hardware.nixosModules.raspberry-pi-5
       
       # Your main configuration file
       ./configuration.nix
     ];
   };
 };

} ```

2. Apply your configuration with:

```bash sudo nixos-rebuild switch --flake .#mydevice ```

The `#mydevice` part corresponds to the `nixosConfigurations.mydevice` entry in your flake.nix file.

      1. Binary Caches
        1. AArch64 (ARM64)

The official NixOS Hydra instance builds full binary sets for the AArch64 architecture, available on https://cache.nixos.org for both the nixpkgs-unstable and stable channels:

```nix nix.settings = {

 substituters = [
   "https://cache.nixos.org"
 ];
 trusted-public-keys = [
   "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
 ];

}; ```

        1. armv6l and armv7l (32-bit ARM)

There are currently no official binary caches for 32-bit ARM. Consider: - Building packages natively (slow on low-power devices) - Using cross-compilation (see below) - Setting up your own binary cache

For better performance on bandwidth-constrained devices, limit parallel connections:

```nix nix.settings = {

 max-substitution-jobs = 2;

}; ```

      1. Building on Resource-Constrained ARM Devices

ARM devices, especially older or low-power models, may struggle with building large packages. Consider these approaches:

        1. 1. Remote Builders

Configure a more powerful machine (ideally ARM64) as a remote builder:

```nix nix.buildMachines = [{

 hostName = "builder";
 system = "aarch64-linux";
 maxJobs = 4;
 speedFactor = 2;
 supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];

}]; nix.distributedBuilds = true; ```

For setup instructions, see the [Distributed Build](https://nixos.wiki/wiki/Distributed_build) wiki page.

        1. 2. Cross-Compilation using QEMU with binfmt_misc

On an x86_64 NixOS system, enable ARM emulation:

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

Then build ARM packages from your x86_64 machine using:

```bash nix build --system aarch64-linux .#package ```

Or for non-Flake commands:

```bash nix-build '<nixpkgs>' -A pkgs.hello --argstr system aarch64-linux ```

        1. 3. Building through QEMU/KVM

While slower than other methods, full emulation through QEMU/KVM is possible for ARM development. See the [NixOS on ARM/QEMU](https://nixos.wiki/wiki/NixOS_on_ARM/QEMU) page for detailed setup.

      1. Creating Custom ARM Images
        1. Building with Flakes (Recommended)

Create a custom SD card image with a Flake:

```nix {

 description = "Custom ARM image";
 
 inputs = {
   nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
 };
 
 outputs = { self, nixpkgs }: {
   nixosConfigurations.armimage = nixpkgs.lib.nixosSystem {
     system = "aarch64-linux"; # For building 64-bit ARM images
     modules = [
       # Base SD image module for your architecture
       "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix"
       # Your customizations
       ({ ... }: {
         # Add your customizations here
         users.users.root.openssh.authorizedKeys.keys = [
           "ssh-ed25519 AAAAC3NzaC1lZDI1.... username@tld"
         ];
       })
     ];
   };
   
   # Make the SD image the default output
   packages.aarch64-linux.default = 
     self.nixosConfigurations.armimage.config.system.build.sdImage;
 };

} ```

Build with:

```bash nix build ```

        1. Building the Traditional Way

For non-Flake builds:

```bash nix-build '<nixpkgs/nixos>' -A config.system.build.sdImage -I nixos-config=./sd-image.nix ```

Where `sd-image.nix` contains:

```nix { ... }: {

 imports = [
   <nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix>
 ];
 
 # Your customizations here
 users.users.root.openssh.authorizedKeys.keys = [
    "ssh-ed25519 AAAAC3NzaC1lZDI1.... username@tld"
 ];

} ```

      1. U-Boot Customization

Some boards may require custom U-Boot builds. For boards supported by upstream U-Boot, you can cross-compile from an x86_64 host:

```bash nix-shell -p 'let plat = pkgsCross.aarch64-multiplatform; in plat.buildUBoot{defconfig = "board_defconfig"; extraMeta.platforms = ["aarch64-linux"];}' ```

Replace `board_defconfig` with your board's U-Boot configuration name.

For manual builds (when NixOS packages are unavailable):

```bash nix-shell -E 'with import <nixpkgs> {}; stdenv.mkDerivation { name = "arm-shell"; buildInputs = [git gnumake gcc gcc-arm-embedded dtc bison flex python3 swig]; }' git clone git://git.denx.de/u-boot.git cd u-boot make CROSS_COMPILE=arm-none-eabi- board_defconfig make CROSS_COMPILE=arm-none-eabi- ```

Flash the resulting U-Boot image to your storage device (SD card/eMMC/etc.) at the appropriate offset, typically:

```bash sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8 ```

The seek value and filename vary by board - check your board's wiki page or documentation.

      1. Optimizing Performance on ARM

For better performance on ARM devices:

```nix {

 # CPU frequency scaling (if supported by your hardware)
 powerManagement.cpuFreqGovernor = "ondemand";
 
 # IO scheduler tuning (improves SD card performance)
 services.udev.extraRules = 
   # Set deadline scheduler for SD cards
   ACTION=="add|change", KERNEL=="mmcblk[0-9]", ATTR{queue/scheduler}="mq-deadline"
 ;
 
 # Zram swap (better than SD card swap)
 zramSwap = {
   enable = true;
   algorithm = "zstd";
 };
 
 # Using tmpfs for temp directories
 boot.tmpOnTmpfs = true;

} ```

      1. Security Hardening for ARM Devices

Since NixOS 25.05, additional security features are available that are relevant for ARM devices:

```nix {

 # Kernel hardening options
 boot.kernelParams = [ "slab_nomerge" "init_on_alloc=1" "init_on_free=1" ];
 boot.kernel.sysctl = {
   "kernel.kptr_restrict" = 2;
   "kernel.dmesg_restrict" = 1;
 };
 
 # Mandatory Access Control (if supported by your hardware)
 security.apparmor.enable = true;  # Less resource-intensive than SELinux
 
 # Memory protection
 security.protectKernelImage = true;

} ```

Note: Always understand the security implications and compatibility impact of hardening options before applying them. Some settings may affect hardware compatibility or performance on specific ARM devices.

      1. Wayland Support on ARM64

Recent NixOS releases provide good Wayland support on ARM64 devices:

```nix {

 # For GNOME
 services.xserver = {
   enable = true;
   displayManager.gdm.enable = true;
   desktopManager.gnome.enable = true;
   displayManager.gdm.wayland = true; # Explicitly enable Wayland
 };
 
 # For KDE Plasma
 services.xserver = {
   enable = true;
   displayManager.sddm.enable = true;
   desktopManager.plasma5.enable = true;
   displayManager.defaultSession = "plasmawayland";
 };
 
 # Required for GPU acceleration
 hardware.opengl = {
   enable = true;
   driSupport = true;
 };

} ```

For Raspberry Pi 5, add `dtoverlay=vc4-kms-v3d-pi5` in `/boot/config.txt` to enable GPU drivers compatible with Wayland.

      1. Common ARM Device Troubleshooting

1. **UART Console Access**: If your device isn't booting properly, enable UART:

  ```nix
  boot.kernelParams = [
    "console=ttyS0,115200n8"  # Adjust ttyS0 to match your device's UART
  ];
  ```
  The actual device (ttyAMA0, ttyS0, ttyS1) depends on your hardware. See the [Enable UART](https://nixos.wiki/wiki/NixOS_on_ARM#Enable_UART) section for details.

2. **Memory Constraints**: For devices with limited RAM:

  ```nix
  nix.settings.cores = 1; # Limit parallel builds
  nix.settings.max-jobs = 1;
  boot.tmp.cleanOnBoot = true; # Clean /tmp on boot
  ```

3. **Network Issues**: For better wireless support:

  ```nix
  networking.networkmanager.enable = true;
  hardware.enableRedistributableFirmware = true; # For WiFi firmware
  ```
      1. Related Projects
        1. NixOS Mobile

For mobile devices like smartphones and tablets, check out the [Mobile NixOS project](https://github.com/mobile-nixos/mobile-nixos). This project extends NixOS to run on devices like the PinePhone and select OnePlus models, with features specifically designed for mobile use cases.

Mobile NixOS provides specialized modules for: - Touch input and mobile-friendly UI - Power management - Cellular modem support - Mobile hardware integration

Visit the [Mobile NixOS documentation](https://mobile.nixos.org/) for detailed setup and configuration guidance.

        1. QEMU Emulation

For detailed instructions on running NixOS ARM in QEMU, see the dedicated [NixOS on ARM/QEMU](https://nixos.wiki/wiki/NixOS_on_ARM/QEMU) wiki page.