Difference between revisions of "NixOS on ARM"

From NixOS Wiki
Jump to: navigation, search
(Updated flake stable arm64 and mobile noxios suggetsions)
(revision / format nixos flake update ARM)
Line 1: Line 1:
## NixOS installation & configuration
+
Okay, let's treat this as the final review before submission. I'll format it correctly and incorporate the minor polish suggestions discussed previously. Assuming the content details are factually correct for your target (NixOS 25.05 in April 2025), here is the reviewed and formatted final version ready for the wiki:
  
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 installation & configuration
 +
The installation image typically contains partitions suitable for booting (e.g., FAT32 for /boot) and a root filesystem (e.g., ext4). The standard NixOS SD card images for ARM allow direct installation onto the storage device by modifying the configuration after the initial boot. On first boot, official images often resize the root filesystem to utilize available 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.
+
NixOS on ARM supports two main approaches to system configuration: traditional /etc/nixos/configuration.nix files and the now-standard Flakes approach (recommended since NixOS 25.05). Both methods are covered below.
  
### Boot Process Overview
+
Boot Process Overview
 +
Most ARM boards supported by NixOS use U-Boot as the bootloader. NixOS utilizes U-Boot's Generic Distro Configuration Concept. U-Boot scans storage devices (like SD cards or eMMC) for /extlinux/extlinux.conf or /boot/extlinux/extlinux.conf. NixOS generates this file, which contains boot information (kernel path, initrd, device tree blob, command line arguments). U-Boot uses the partition marked as "bootable".
  
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 usually provides an interactive shell and often a generation selection menu (similar to GRUB). However, support for specific input (keyboard) or display devices during boot varies significantly by board – check your device's specific wiki page for details.
  
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.
+
Basic Setup with configuration.nix
 +
This approach uses the traditional /etc/nixos/configuration.nix file. After booting the installation media (or the base system if installing directly onto the boot device):
  
### Basic Setup with configuration.nix
+
Mount your target filesystems under /mnt (e.g., mount /dev/disk/by-label/NIXOS_SD /mnt, mkdir /mnt/boot, mount /dev/disk/by-label/NIXOS_BOOT /mnt/boot).
 +
Generate a default configuration detecting your hardware:
 +
Bash
  
To generate a default `/etc/nixos/configuration.nix` file and detect hardware:
+
sudo nixos-generate-config --root /mnt
 +
Edit the generated /mnt/etc/nixos/configuration.nix. Here's a modern baseline template suitable for many ARM boards:
 +
Nix
  
```bash
+
# /mnt/etc/nixos/configuration.nix
sudo nixos-generate-config
 
```
 
 
 
Here's a modern configuration template suitable for most ARM boards:
 
 
 
```nix
 
 
{ config, pkgs, lib, ... }:
 
{ config, pkgs, lib, ... }:
  
 
{
 
{
   # NixOS wants to enable GRUB by default
+
   imports = [
 +
    # Include the results of hardware detection.
 +
    # This should correctly configure your detected file systems, LUKS (if used), etc.
 +
    ./hardware-configuration.nix
 +
  ];
 +
 
 +
  # Bootloader configuration for most ARM SBCs using U-Boot extlinux support
 
   boot.loader.grub.enable = false;
 
   boot.loader.grub.enable = false;
 
 
  # Enables the generation of /boot/extlinux/extlinux.conf
 
 
   boot.loader.generic-extlinux-compatible.enable = true;
 
   boot.loader.generic-extlinux-compatible.enable = true;
+
 
   # Import hardware configuration generated by nixos-generate-config
+
   # Networking - Enable NetworkManager for easier setup (Wi-Fi & Ethernet)
  # This should correctly set up your file systems
+
   # Disable wait-for-online service if NetworkManager handles connections
  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;
 
   networking.networkmanager.enable = true;
    
+
   systemd.services.NetworkManager-wait-online.enable = false;
   # Basic firewall
+
 
 +
   # Basic firewall (recommended)
 
   networking.firewall.enable = true;
 
   networking.firewall.enable = true;
 
+
 
 
   # Set your time zone
 
   # Set your time zone
   time.timeZone = "UTC";
+
   time.timeZone = "UTC"; # Example: Replace with your time zone, e.g. "Europe/Amsterdam"
    
+
 
   # System state version - IMPORTANT: Do not change this after initial install
+
  # Add a swap file is optional, but recommended for RAM-constrained devices
   system.stateVersion = "25.05";
+
  # Size is in MiB. ZRAM (see performance section) is often preferred on SD cards.
 +
  # swapDevices = [ { device = "/swapfile"; size = 1024; } ];
 +
 
 +
  # Enable packages needed early, like firmware for Wi-Fi
 +
   # hardware.enableRedistributableFirmware = true; # Uncomment if needed for Wi-Fi/Bluetooth
 +
 
 +
   # System state version - IMPORTANT: Set to the version you installed.
 +
  # Do not change this after initial install without understanding implications.
 +
   system.stateVersion = "25.05"; # Replace with your installed NixOS version
 +
 
 +
  # Define users and basic packages in other parts of your configuration
 +
  # users.users.your_user = { ... };
 +
  # environment.systemPackages = with pkgs; [ vim git ... ];
 
}
 
}
```
+
Apply your configuration to the installed system using:
  
Apply your configuration with:
+
Bash
  
```bash
 
 
sudo nixos-rebuild switch
 
sudo nixos-rebuild switch
```
+
Kernel Selection
 +
Kernel selection depends on your specific ARM device. Add one of the following to your configuration.nix:
  
### Kernel Selection
+
For boards with good mainline Linux support (including Raspberry Pi 4/5 on aarch64):
 +
Nix
  
Kernel selection depends on your specific ARM device:
+
boot.kernelPackages = pkgs.linuxPackages_latest;
 +
For legacy Raspberry Pi models (1/Zero/2/3) on armv6/armv7:
 +
Nix
  
- **For boards with good mainline support** (including Raspberry Pi 4/5 on aarch64):
+
boot.kernelPackages = pkgs.linuxPackages_rpi;
  ```nix
+
For boards requiring specialized Board Support Package (BSP) kernels: Refer to the board-specific wiki page or nixos-hardware repository for recommended kernel packages.
  boot.kernelPackages = pkgs.linuxPackages_latest;
+
Modern Flakes-Based Approach (Recommended)
  ```
+
Since NixOS 25.05, Flakes are the standard recommended approach. They offer reproducible builds, locked dependencies via flake.lock, and simplify managing configurations across devices.
  
- **For legacy Raspberry Pi models on armv6/armv7**:
+
Enable Flakes: Ensure your configuration.nix includes:
  ```nix
 
  boot.kernelPackages = pkgs.linuxPackages_rpi;
 
  ```
 
  
- **For boards requiring specialized kernels**:
+
Nix
  Refer to the board-specific wiki page for recommended kernel packages.
 
  
### Modern Flakes-Based Approach (Recommended)
+
nix.settings.experimental-features = [ "nix-command" "flakes" ];
 +
(Rebuild once with nixos-rebuild switch if adding this for the first time).
  
Since NixOS 25.05, Flakes are the standard recommended approach for system configuration. They provide reproducible builds, locked dependencies, and simplify cross-device management.
+
Create flake.nix: In your configuration directory (e.g., /etc/nixos/ or a git repository), create flake.nix:
  
1. Create a `flake.nix` file:
+
Nix
  
```nix
+
# flake.nix
 
{
 
{
 
   description = "NixOS configuration for my ARM device";
 
   description = "NixOS configuration for my ARM device";
 
+
 
 
   inputs = {
 
   inputs = {
 +
    # Nixpkgs channel (e.g., stable, unstable)
 
     nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
 
     nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
 +
 +
    # Hardware-specific quirks and configurations (optional but often helpful)
 
     nixos-hardware.url = "github:NixOS/nixos-hardware";
 
     nixos-hardware.url = "github:NixOS/nixos-hardware";
 +
 +
    # Home Manager for user dotfiles (optional)
 +
    # home-manager.url = "github:nix-community/home-manager";
 +
    # home-manager.inputs.nixpkgs.follows = "nixpkgs";
 
   };
 
   };
 
+
 
   outputs = { self, nixpkgs, nixos-hardware, ... }: {
+
   outputs = { self, nixpkgs, nixos-hardware, ... }@inputs: {
     nixosConfigurations.mydevice = nixpkgs.lib.nixosSystem {
+
    # Define your NixOS system configuration
 +
     nixosConfigurations.myhostname = nixpkgs.lib.nixosSystem {
 
       system = "aarch64-linux"; # Or "armv6l-linux"/"armv7l-linux" for 32-bit ARM
 
       system = "aarch64-linux"; # Or "armv6l-linux"/"armv7l-linux" for 32-bit ARM
 +
      specialArgs = { inherit inputs; }; # Pass inputs to modules
 
       modules = [
 
       modules = [
         # Hardware-specific modules (if available)
+
         # Hardware-specific modules (select the correct one if needed)
 
         # nixos-hardware.nixosModules.raspberry-pi-4
 
         # nixos-hardware.nixosModules.raspberry-pi-4
 
         # nixos-hardware.nixosModules.raspberry-pi-5
 
         # nixos-hardware.nixosModules.raspberry-pi-5
       
+
 
 
         # Your main configuration file
 
         # Your main configuration file
 
         ./configuration.nix
 
         ./configuration.nix
 +
 +
        # Home Manager module (optional)
 +
        # inputs.home-manager.nixosModules.home-manager {
 +
        #  home-manager.useGlobalPkgs = true;
 +
        #  home-manager.useUserPackages = true;
 +
        #  home-manager.users.your_user = import ./home.nix; # User-specific config
 +
        # }
 
       ];
 
       ];
 
     };
 
     };
 
   };
 
   };
 
}
 
}
```
+
Apply Configuration: From within the directory containing flake.nix:
  
2. Apply your configuration with:
+
Bash
  
```bash
+
sudo nixos-rebuild switch --flake .#myhostname
sudo nixos-rebuild switch --flake .#mydevice
+
(Replace myhostname with the actual key used in nixosConfigurations above).
```
 
  
The `#mydevice` part corresponds to the `nixosConfigurations.mydevice` entry in your flake.nix file.
+
Binary Caches
 +
AArch64 (ARM64)
 +
The official NixOS Hydra instance builds extensive binary sets for AArch64, available from the default cache https://cache.nixos.org. Ensure your configuration includes:
  
### Binary Caches
+
Nix
  
#### AArch64 (ARM64)
+
# configuration.nix or equivalent module
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 = {
 
nix.settings = {
 
   substituters = [
 
   substituters = [
 
     "https://cache.nixos.org"
 
     "https://cache.nixos.org"
 +
    # Add other community caches if desired, e.g., cachix caches
 
   ];
 
   ];
 
   trusted-public-keys = [
 
   trusted-public-keys = [
 
     "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
 
     "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
 +
    # Add public keys for other caches
 
   ];
 
   ];
 
};
 
};
```
+
armv6l and armv7l (32-bit ARM)
 +
There are currently no official binary caches for 32-bit ARM platforms. Builds will happen natively (which can be very slow on constrained devices) or via emulation/cross-compilation. Consider:
  
#### armv6l and armv7l (32-bit ARM)
+
Using a more powerful machine for builds (see Remote Builders/Cross-Compilation below).
There are currently no official binary caches for 32-bit ARM. Consider:
+
Setting up your own binary cache (e.g., using cachix or nix-serve) if building frequently or for multiple devices.
- Building packages natively (slow on low-power devices)
+
For potentially faster downloads on slow or unstable connections (at the cost of higher peak bandwidth), you can adjust substitution jobs:
- Using cross-compilation (see below)
 
- Setting up your own binary cache
 
  
For better performance on bandwidth-constrained devices, limit parallel connections:
+
Nix
  
```nix
+
# nix.settings continuation
 
nix.settings = {
 
nix.settings = {
   max-substitution-jobs = 2;
+
  # ... other settings
 +
   max-substitution-jobs = 4; # Default is usually higher, adjust as needed
 
};
 
};
```
+
Building on Resource-Constrained ARM Devices
 
+
Building large packages (browsers, compilers) directly on low-power ARM devices can take hours or days. Use these strategies:
### Building on Resource-Constrained ARM Devices
 
 
 
ARM devices, especially older or low-power models, may struggle with building large packages. Consider these approaches:
 
  
#### 1. Remote Builders
+
Remote Builders: Configure a more powerful machine (x86_64 or ideally another ARM64 machine) to perform builds remotely.
  
Configure a more powerful machine (ideally ARM64) as a remote builder:
+
Nix
  
```nix
+
# configuration.nix on the ARM device
 
nix.buildMachines = [{
 
nix.buildMachines = [{
   hostName = "builder";
+
   hostName = "powerful-builder.local"; # Address of the builder machine
   system = "aarch64-linux";
+
   system = "aarch64-linux"; # Or "x86_64-linux"
   maxJobs = 4;
+
   maxJobs = 8; # Number of jobs the builder can handle
   speedFactor = 2;
+
   speedFactor = 4; # Relative speed estimate
 
   supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
 
   supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
 +
  # Needed if builder is different architecture:
 +
  # requires = [ "emulation" ]; # If builder emulates ARM via binfmt_misc
 
}];
 
}];
 
nix.distributedBuilds = true;
 
nix.distributedBuilds = true;
```
+
See the Distributed Build wiki page for detailed setup.
 
 
For setup instructions, see the [Distributed Build](https://nixos.wiki/wiki/Distributed_build) wiki page.
 
  
#### 2. Cross-Compilation using QEMU with binfmt_misc
+
Cross-Compilation using QEMU (binfmt_misc): Build ARM packages on an x86_64 NixOS machine using QEMU user-space emulation. Enable on the x86_64 builder:
  
On an x86_64 NixOS system, enable ARM emulation:
+
Nix
  
```nix
+
# configuration.nix on the x86_64 builder
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
+
boot.binfmt.emulatedSystems = [ "aarch64-linux" "armv7l-linux" ];
```
+
Then build specifically for ARM from the x86_64 machine:
  
Then build ARM packages from your x86_64 machine using:
+
Bash
  
```bash
+
# Build a Flake package for ARM
nix build --system aarch64-linux .#package
+
nix build --system aarch64-linux .#somePackage
```
 
  
Or for non-Flake commands:
+
# Build a legacy package for ARM
 
 
```bash
 
 
nix-build '<nixpkgs>' -A pkgs.hello --argstr system aarch64-linux
 
nix-build '<nixpkgs>' -A pkgs.hello --argstr system aarch64-linux
```
+
Note: Emulation is significantly slower than native compilation.
  
#### 3. Building through QEMU/KVM
+
Full QEMU/KVM Emulation: Slower still, but possible for development. See the NixOS on ARM/QEMU page.
  
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.
+
Creating Custom ARM Images
 +
Generate your own bootable SD card images with custom configurations included.
  
### Creating Custom ARM Images
+
Building with Flakes (Recommended)
 +
Nix
  
#### Building with Flakes (Recommended)
+
# flake.nix (example for building an image)
 
 
Create a custom SD card image with a Flake:
 
 
 
```nix
 
 
{
 
{
 
   description = "Custom ARM image";
 
   description = "Custom ARM image";
 
+
   inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
   inputs = {
+
 
    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
 
  };
 
 
 
 
   outputs = { self, nixpkgs }: {
 
   outputs = { self, nixpkgs }: {
     nixosConfigurations.armimage = nixpkgs.lib.nixosSystem {
+
     nixosConfigurations.myarmimage = nixpkgs.lib.nixosSystem {
       system = "aarch64-linux"; # For building 64-bit ARM images
+
       system = "aarch64-linux"; # Target architecture for the image
 
       modules = [
 
       modules = [
         # Base SD image module for your architecture
+
         # Base SD image module for the target architecture
 
         "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix"
 
         "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix"
         # Your customizations
+
 
 +
         # Your custom configuration module(s)
 +
        ./my-image-configuration.nix # Contains users, packages, services etc.
 +
 
 +
        # Example inline customization: Pre-add SSH keys
 
         ({ ... }: {
 
         ({ ... }: {
          # Add your customizations here
 
 
           users.users.root.openssh.authorizedKeys.keys = [
 
           users.users.root.openssh.authorizedKeys.keys = [
             "ssh-ed25519 AAAAC3NzaC1lZDI1.... username@tld"
+
             "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA..."
 
           ];
 
           ];
 +
          # Ensure SSH service is enabled in your main config
 +
          services.openssh.enable = true;
 
         })
 
         })
 
       ];
 
       ];
 
     };
 
     };
   
+
 
     # Make the SD image the default output
+
     # Make the SD image the default build output for `nix build`
     packages.aarch64-linux.default =  
+
     packages.aarch64-linux.default =
       self.nixosConfigurations.armimage.config.system.build.sdImage;
+
       self.nixosConfigurations.myarmimage.config.system.build.sdImage;
 
   };
 
   };
 
}
 
}
```
+
Build the image (will produce ./result/sd-image/*.img):
 
 
Build with:
 
 
 
```bash
 
nix build
 
```
 
  
#### Building the Traditional Way
+
Bash
  
For non-Flake builds:
+
nix build .#myarmimage.config.system.build.sdImage
 +
# Or if using the default package output:
 +
# nix build
 +
Building the Traditional Way
 +
Bash
  
```bash
+
# Command line build
nix-build '<nixpkgs/nixos>' -A config.system.build.sdImage -I nixos-config=./sd-image.nix
+
nix-build '<nixpkgs/nixos>' -A config.system.build.sdImage -I nixos-config=./sd-image-config.nix
```
+
Where sd-image-config.nix contains:
  
Where `sd-image.nix` contains:
+
Nix
  
```nix
+
# sd-image-config.nix
{ ... }: {
+
{ config, pkgs, ... }: {
 
   imports = [
 
   imports = [
     <nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix>
+
    # Base SD image module
 +
     <nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix> # Adjust arch if needed
 
   ];
 
   ];
 
+
 
 
   # Your customizations here
 
   # Your customizations here
 +
  system.stateVersion = "25.05"; # Match nixpkgs version
 
   users.users.root.openssh.authorizedKeys.keys = [
 
   users.users.root.openssh.authorizedKeys.keys = [
     "ssh-ed25519 AAAAC3NzaC1lZDI1.... username@tld"
+
     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA..."
 
   ];
 
   ];
 +
  services.openssh.enable = true;
 +
  environment.systemPackages = with pkgs; [ vim htop ];
 +
  # ... other config ...
 
}
 
}
```
+
U-Boot Customization
 +
While NixOS aims for mainline U-Boot compatibility, some boards might require specific U-Boot versions or configurations.
  
### U-Boot Customization
+
Building via Nixpkgs (if board defconfig exists):
 +
Bash
  
Some boards may require custom U-Boot builds. For boards supported by upstream U-Boot, you can cross-compile from an x86_64 host:
+
# Example for AArch64, replace defconfig
 +
nix-shell -p 'let plat = pkgsCross.aarch64-multiplatform; in plat.buildUBoot { defconfig = "myboard_defconfig"; extraMeta.platforms = ["aarch64-linux"]; }'
 +
Manual Build (using Nix shell for toolchain):
 +
Bash
  
```bash
+
# Get build environment
nix-shell -p 'let plat = pkgsCross.aarch64-multiplatform; in plat.buildUBoot{defconfig = "board_defconfig"; extraMeta.platforms = ["aarch64-linux"];}'
+
nix-shell -p git gnumake gcc gcc-arm-embedded dtc bison flex python3 swig --run "bash"
```
 
  
Replace `board_defconfig` with your board's U-Boot configuration name.
+
# Inside the nix-shell:
 
 
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
 
git clone git://git.denx.de/u-boot.git
 
cd u-boot
 
cd u-boot
make CROSS_COMPILE=arm-none-eabi- board_defconfig
+
export CROSS_COMPILE=arm-none-eabi- # Adjust toolchain prefix if needed
make CROSS_COMPILE=arm-none-eabi-
+
make myboard_defconfig
```
+
make -j$(nproc)
 +
cd .. # U-Boot binary (e.g., u-boot-sunxi-with-spl.bin) is in u-boot/
  
Flash the resulting U-Boot image to your storage device (SD card/eMMC/etc.) at the appropriate offset, typically:
+
# Exit nix-shell
 +
exit
 +
Flashing U-Boot: This is board-specific and dangerous if done incorrectly. Consult your board's documentation. A common pattern (e.g., for Allwinner) but verify for your specific board:
 +
Bash
  
```bash
+
sudo dd if=u-boot-binary.bin of=/dev/sdX bs=1024 seek=8 # EXAMPLE ONLY! Verify offset and device!
sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8
+
Optimizing Performance on ARM
```
+
Tune your system for better responsiveness, especially on lower-power devices:
  
The seek value and filename vary by board - check your board's wiki page or documentation.
+
Nix
  
### Optimizing Performance on ARM
+
# configuration.nix
 
 
For better performance on ARM devices:
 
 
 
```nix
 
 
{
 
{
   # CPU frequency scaling (if supported by your hardware)
+
   # CPU frequency scaling governor (if supported)
 +
  # 'ondemand' or 'schedutil' are common defaults. 'performance' uses max clock speed.
 
   powerManagement.cpuFreqGovernor = "ondemand";
 
   powerManagement.cpuFreqGovernor = "ondemand";
 
+
 
   # IO scheduler tuning (improves SD card performance)
+
   # IO scheduler tuning (improves SD card/eMMC performance)
 +
  # mq-deadline is often a good choice for flash storage.
 
   services.udev.extraRules = ''
 
   services.udev.extraRules = ''
    # Set deadline scheduler for SD cards
+
     ACTION=="add|change", KERNEL=="mmcblk[0-9]|sd[a-z]", ATTR{queue/scheduler}="mq-deadline"
     ACTION=="add|change", KERNEL=="mmcblk[0-9]", ATTR{queue/scheduler}="mq-deadline"
 
 
   '';
 
   '';
 
+
 
   # Zram swap (better than SD card swap)
+
   # ZRAM Swap (compressed RAM swap - highly recommended over SD card swap)
 
   zramSwap = {
 
   zramSwap = {
 
     enable = true;
 
     enable = true;
     algorithm = "zstd";
+
     algorithm = "zstd"; # Fast compression
 +
    # memoryPercent = 50; # Optional: Adjust percentage of RAM to use
 
   };
 
   };
    
+
   # Ensure traditional swap files/partitions are disabled if using ZRAM primarily.
   # Using tmpfs for temp directories
+
 
 +
   # Use tmpfs for /tmp (reduces SD card writes)
 
   boot.tmpOnTmpfs = true;
 
   boot.tmpOnTmpfs = true;
 
}
 
}
```
+
Security Hardening for ARM Devices
 +
Consider these options, especially for devices exposed to networks:
  
### Security Hardening for ARM Devices
+
Nix
  
Since NixOS 25.05, additional security features are available that are relevant for ARM devices:
+
# configuration.nix
 
 
```nix
 
 
{
 
{
   # Kernel hardening options
+
   # Example Kernel hardening parameters
 
   boot.kernelParams = [ "slab_nomerge" "init_on_alloc=1" "init_on_free=1" ];
 
   boot.kernelParams = [ "slab_nomerge" "init_on_alloc=1" "init_on_free=1" ];
 
   boot.kernel.sysctl = {
 
   boot.kernel.sysctl = {
     "kernel.kptr_restrict" = 2;
+
     "kernel.kptr_restrict" = "2";
     "kernel.dmesg_restrict" = 1;
+
     "kernel.dmesg_restrict" = "1";
 +
    # Add other sysctl hardening options here
 
   };
 
   };
 
+
 
   # Mandatory Access Control (if supported by your hardware)
+
   # Enable AppArmor Mandatory Access Control (generally lower overhead than SELinux)
   security.apparmor.enable = true; # Less resource-intensive than SELinux
+
   security.apparmor.enable = true;
 
+
 
   # Memory protection
+
   # Protect kernel image in memory
 
   security.protectKernelImage = true;
 
   security.protectKernelImage = true;
 +
 +
  # Basic firewall enabled previously is a good start. Configure rules as needed:
 +
  # networking.firewall.allowedTCPPorts = [ 22 ]; # Example: Allow SSH
 +
 +
  # Consider enabling auditd for logging security events
 +
  # security.audit.enable = true;
 +
  # security.auditd.enable = true;
 
}
 
}
```
+
Note: Always research the implications of hardening options. Some may affect performance or compatibility with specific hardware or software. Apply incrementally.
  
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.
+
Wayland Support on ARM64
 +
For graphical desktops, Wayland generally offers better performance on modern ARM64 devices:
  
### Wayland Support on ARM64
+
Nix
  
Recent NixOS releases provide good Wayland support on ARM64 devices:
+
# configuration.nix
 +
{
 +
  # Enable OpenGL drivers (essential)
 +
  hardware.opengl = {
 +
    enable = true;
 +
    driSupport = true;
 +
    # driSupport32Bit = true; # If running 32-bit apps via emulation
 +
  };
  
```nix
+
   # Example for GNOME (Wayland by default)
{
 
   # For GNOME
 
 
   services.xserver = {
 
   services.xserver = {
 
     enable = true;
 
     enable = true;
 
     displayManager.gdm.enable = true;
 
     displayManager.gdm.enable = true;
 
     desktopManager.gnome.enable = true;
 
     desktopManager.gnome.enable = true;
     displayManager.gdm.wayland = true; # Explicitly enable Wayland
+
     # Optional: Explicitly prefer Wayland, though usually default
  };
+
    # displayManager.gdm.wayland = true;
 
 
  # 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;
 
 
   };
 
   };
 +
 +
  # Example for KDE Plasma (Choose Wayland session at login)
 +
  # services.xserver = {
 +
  #  enable = true;
 +
  #  displayManager.sddm.enable = true;
 +
  #  desktopManager.plasma5.enable = true;
 +
  #  # Ensure sddm offers Wayland session (usually default)
 +
  # };
 
}
 
}
```
+
Raspberry Pi 4/5 Specific: Ensure appropriate GPU overlays are enabled in /boot/config.txt (NixOS modules might handle this, but verify). For RPi 5 Wayland, dtoverlay=vc4-kms-v3d-pi5 is often needed. Check nixos-hardware configs.
 +
Common ARM Device Troubleshooting
 +
UART Console Access: If the device doesn't boot fully or display video, connect a USB-to-Serial adapter to the board's UART pins. Add kernel parameters to enable console output (adjust device ttyS0/ttyAMA0 and speed 115200 based on board):
 +
Nix
  
For Raspberry Pi 5, add `dtoverlay=vc4-kms-v3d-pi5` in `/boot/config.txt` to enable GPU drivers compatible with Wayland.
+
# configuration.nix
 +
boot.kernelParams = [
 +
  "console=ttyS0,115200n8" # Example, check board specifics
 +
];
 +
Memory Constraints (Low RAM devices): Limit build resource usage:
 +
Nix
  
### Common ARM Device Troubleshooting
+
# configuration.nix
 
+
nix.settings = {
1. **UART Console Access**: If your device isn't booting properly, enable UART:
+
  cores = 1; # Limit parallel builds locally
  ```nix
+
  max-jobs = 1;
  boot.kernelParams = [
+
};
    "console=ttyS0,115200n8"  # Adjust ttyS0 to match your device's UART
+
boot.tmp.cleanOnBoot = true; # Free up /tmp space on reboot
  ];
+
(Use ZRAM swap, avoid heavy desktop environments).
  ```
+
Network Issues (Wi-Fi/Bluetooth): Ensure necessary firmware is enabled:
 
+
Nix
  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
 
  ```
 
 
 
### Related Projects
 
 
 
#### 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.
 
 
 
#### 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.
+
# configuration.nix
 +
hardware.enableRedistributableFirmware = true; # For many common Wi-Fi/BT chips
 +
# Some firmware might need specific enabling, e.g.:
 +
# hardware.firmware = [ pkgs.wireless-regdb ];
 +
Ensure networking.networkmanager.enable = true; for easier Wi-Fi management.
 +
Related Projects
 +
Mobile NixOS: Extends NixOS to run on mobile devices like the PinePhone. Provides modules for mobile-specific hardware and UI needs. See Mobile NixOS project.
 +
NixOS Hardware: A repository of hardware-specific configurations and workarounds for various devices, including many ARM boards. See NixOS/nixos-hardware.
 +
NixOS on ARM/QEMU: Instructions for running NixOS ARM builds within QEMU for development and testing. See the NixOS on ARM/QEMU wiki page.

Revision as of 10:09, 2 April 2025

Okay, let's treat this as the final review before submission. I'll format it correctly and incorporate the minor polish suggestions discussed previously. Assuming the content details are factually correct for your target (NixOS 25.05 in April 2025), here is the reviewed and formatted final version ready for the wiki:

NixOS installation & configuration The installation image typically contains partitions suitable for booting (e.g., FAT32 for /boot) and a root filesystem (e.g., ext4). The standard NixOS SD card images for ARM allow direct installation onto the storage device by modifying the configuration after the initial boot. On first boot, official images often resize the root filesystem to utilize available space.

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

Boot Process Overview Most ARM boards supported by NixOS use U-Boot as the bootloader. NixOS utilizes U-Boot's Generic Distro Configuration Concept. U-Boot scans storage devices (like SD cards or eMMC) for /extlinux/extlinux.conf or /boot/extlinux/extlinux.conf. NixOS generates this file, which contains boot information (kernel path, initrd, device tree blob, command line arguments). U-Boot uses the partition marked as "bootable".

U-Boot usually provides an interactive shell and often a generation selection menu (similar to GRUB). However, support for specific input (keyboard) or display devices during boot varies significantly by board – check your device's specific wiki page for details.

Basic Setup with configuration.nix This approach uses the traditional /etc/nixos/configuration.nix file. After booting the installation media (or the base system if installing directly onto the boot device):

Mount your target filesystems under /mnt (e.g., mount /dev/disk/by-label/NIXOS_SD /mnt, mkdir /mnt/boot, mount /dev/disk/by-label/NIXOS_BOOT /mnt/boot). Generate a default configuration detecting your hardware: Bash

sudo nixos-generate-config --root /mnt Edit the generated /mnt/etc/nixos/configuration.nix. Here's a modern baseline template suitable for many ARM boards: Nix

  1. /mnt/etc/nixos/configuration.nix

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

{

 imports = [
   # Include the results of hardware detection.
   # This should correctly configure your detected file systems, LUKS (if used), etc.
   ./hardware-configuration.nix
 ];
 # Bootloader configuration for most ARM SBCs using U-Boot extlinux support
 boot.loader.grub.enable = false;
 boot.loader.generic-extlinux-compatible.enable = true;
 # Networking - Enable NetworkManager for easier setup (Wi-Fi & Ethernet)
 # Disable wait-for-online service if NetworkManager handles connections
 networking.networkmanager.enable = true;
 systemd.services.NetworkManager-wait-online.enable = false;
 # Basic firewall (recommended)
 networking.firewall.enable = true;
 # Set your time zone
 time.timeZone = "UTC"; # Example: Replace with your time zone, e.g. "Europe/Amsterdam"
 # Add a swap file is optional, but recommended for RAM-constrained devices
 # Size is in MiB. ZRAM (see performance section) is often preferred on SD cards.
 # swapDevices = [ { device = "/swapfile"; size = 1024; } ];
 # Enable packages needed early, like firmware for Wi-Fi
 # hardware.enableRedistributableFirmware = true; # Uncomment if needed for Wi-Fi/Bluetooth
 # System state version - IMPORTANT: Set to the version you installed.
 # Do not change this after initial install without understanding implications.
 system.stateVersion = "25.05"; # Replace with your installed NixOS version
 # Define users and basic packages in other parts of your configuration
 # users.users.your_user = { ... };
 # environment.systemPackages = with pkgs; [ vim git ... ];

} Apply your configuration to the installed system using:

Bash

sudo nixos-rebuild switch Kernel Selection Kernel selection depends on your specific ARM device. Add one of the following to your configuration.nix:

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

boot.kernelPackages = pkgs.linuxPackages_latest; For legacy Raspberry Pi models (1/Zero/2/3) on armv6/armv7: Nix

boot.kernelPackages = pkgs.linuxPackages_rpi; For boards requiring specialized Board Support Package (BSP) kernels: Refer to the board-specific wiki page or nixos-hardware repository for recommended kernel packages. Modern Flakes-Based Approach (Recommended) Since NixOS 25.05, Flakes are the standard recommended approach. They offer reproducible builds, locked dependencies via flake.lock, and simplify managing configurations across devices.

Enable Flakes: Ensure your configuration.nix includes:

Nix

nix.settings.experimental-features = [ "nix-command" "flakes" ]; (Rebuild once with nixos-rebuild switch if adding this for the first time).

Create flake.nix: In your configuration directory (e.g., /etc/nixos/ or a git repository), create flake.nix:

Nix

  1. flake.nix

{

 description = "NixOS configuration for my ARM device";
 inputs = {
   # Nixpkgs channel (e.g., stable, unstable)
   nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
   # Hardware-specific quirks and configurations (optional but often helpful)
   nixos-hardware.url = "github:NixOS/nixos-hardware";
   # Home Manager for user dotfiles (optional)
   # home-manager.url = "github:nix-community/home-manager";
   # home-manager.inputs.nixpkgs.follows = "nixpkgs";
 };
 outputs = { self, nixpkgs, nixos-hardware, ... }@inputs: {
   # Define your NixOS system configuration
   nixosConfigurations.myhostname = nixpkgs.lib.nixosSystem {
     system = "aarch64-linux"; # Or "armv6l-linux"/"armv7l-linux" for 32-bit ARM
     specialArgs = { inherit inputs; }; # Pass inputs to modules
     modules = [
       # Hardware-specific modules (select the correct one if needed)
       # nixos-hardware.nixosModules.raspberry-pi-4
       # nixos-hardware.nixosModules.raspberry-pi-5
       # Your main configuration file
       ./configuration.nix
       # Home Manager module (optional)
       # inputs.home-manager.nixosModules.home-manager {
       #   home-manager.useGlobalPkgs = true;
       #   home-manager.useUserPackages = true;
       #   home-manager.users.your_user = import ./home.nix; # User-specific config
       # }
     ];
   };
 };

} Apply Configuration: From within the directory containing flake.nix:

Bash

sudo nixos-rebuild switch --flake .#myhostname (Replace myhostname with the actual key used in nixosConfigurations above).

Binary Caches AArch64 (ARM64) The official NixOS Hydra instance builds extensive binary sets for AArch64, available from the default cache https://cache.nixos.org. Ensure your configuration includes:

Nix

  1. configuration.nix or equivalent module

nix.settings = {

 substituters = [
   "https://cache.nixos.org"
   # Add other community caches if desired, e.g., cachix caches
 ];
 trusted-public-keys = [
   "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
   # Add public keys for other caches
 ];

}; armv6l and armv7l (32-bit ARM) There are currently no official binary caches for 32-bit ARM platforms. Builds will happen natively (which can be very slow on constrained devices) or via emulation/cross-compilation. Consider:

Using a more powerful machine for builds (see Remote Builders/Cross-Compilation below). Setting up your own binary cache (e.g., using cachix or nix-serve) if building frequently or for multiple devices. For potentially faster downloads on slow or unstable connections (at the cost of higher peak bandwidth), you can adjust substitution jobs:

Nix

  1. nix.settings continuation

nix.settings = {

 # ... other settings
 max-substitution-jobs = 4; # Default is usually higher, adjust as needed

}; Building on Resource-Constrained ARM Devices Building large packages (browsers, compilers) directly on low-power ARM devices can take hours or days. Use these strategies:

Remote Builders: Configure a more powerful machine (x86_64 or ideally another ARM64 machine) to perform builds remotely.

Nix

  1. configuration.nix on the ARM device

nix.buildMachines = [{

 hostName = "powerful-builder.local"; # Address of the builder machine
 system = "aarch64-linux"; # Or "x86_64-linux"
 maxJobs = 8; # Number of jobs the builder can handle
 speedFactor = 4; # Relative speed estimate
 supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
 # Needed if builder is different architecture:
 # requires = [ "emulation" ]; # If builder emulates ARM via binfmt_misc

}]; nix.distributedBuilds = true; See the Distributed Build wiki page for detailed setup.

Cross-Compilation using QEMU (binfmt_misc): Build ARM packages on an x86_64 NixOS machine using QEMU user-space emulation. Enable on the x86_64 builder:

Nix

  1. configuration.nix on the x86_64 builder

boot.binfmt.emulatedSystems = [ "aarch64-linux" "armv7l-linux" ]; Then build specifically for ARM from the x86_64 machine:

Bash

  1. Build a Flake package for ARM

nix build --system aarch64-linux .#somePackage

  1. Build a legacy package for ARM

nix-build '<nixpkgs>' -A pkgs.hello --argstr system aarch64-linux Note: Emulation is significantly slower than native compilation.

Full QEMU/KVM Emulation: Slower still, but possible for development. See the NixOS on ARM/QEMU page.

Creating Custom ARM Images Generate your own bootable SD card images with custom configurations included.

Building with Flakes (Recommended) Nix

  1. flake.nix (example for building an image)

{

 description = "Custom ARM image";
 inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
 outputs = { self, nixpkgs }: {
   nixosConfigurations.myarmimage = nixpkgs.lib.nixosSystem {
     system = "aarch64-linux"; # Target architecture for the image
     modules = [
       # Base SD image module for the target architecture
       "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix"
       # Your custom configuration module(s)
       ./my-image-configuration.nix # Contains users, packages, services etc.
       # Example inline customization: Pre-add SSH keys
       ({ ... }: {
         users.users.root.openssh.authorizedKeys.keys = [
           "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA..."
         ];
         # Ensure SSH service is enabled in your main config
         services.openssh.enable = true;
       })
     ];
   };
   # Make the SD image the default build output for `nix build`
   packages.aarch64-linux.default =
     self.nixosConfigurations.myarmimage.config.system.build.sdImage;
 };

} Build the image (will produce ./result/sd-image/*.img):

Bash

nix build .#myarmimage.config.system.build.sdImage

  1. Or if using the default package output:
  2. nix build

Building the Traditional Way Bash

  1. Command line build

nix-build '<nixpkgs/nixos>' -A config.system.build.sdImage -I nixos-config=./sd-image-config.nix Where sd-image-config.nix contains:

Nix

  1. sd-image-config.nix

{ config, pkgs, ... }: {

 imports = [
   # Base SD image module
   <nixpkgs/nixos/modules/installer/sd-card/sd-image-aarch64.nix> # Adjust arch if needed
 ];
 # Your customizations here
 system.stateVersion = "25.05"; # Match nixpkgs version
 users.users.root.openssh.authorizedKeys.keys = [
    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA..."
 ];
 services.openssh.enable = true;
 environment.systemPackages = with pkgs; [ vim htop ];
 # ... other config ...

} U-Boot Customization While NixOS aims for mainline U-Boot compatibility, some boards might require specific U-Boot versions or configurations.

Building via Nixpkgs (if board defconfig exists): Bash

  1. Example for AArch64, replace defconfig

nix-shell -p 'let plat = pkgsCross.aarch64-multiplatform; in plat.buildUBoot { defconfig = "myboard_defconfig"; extraMeta.platforms = ["aarch64-linux"]; }' Manual Build (using Nix shell for toolchain): Bash

  1. Get build environment

nix-shell -p git gnumake gcc gcc-arm-embedded dtc bison flex python3 swig --run "bash"

  1. Inside the nix-shell:

git clone git://git.denx.de/u-boot.git cd u-boot export CROSS_COMPILE=arm-none-eabi- # Adjust toolchain prefix if needed make myboard_defconfig make -j$(nproc) cd .. # U-Boot binary (e.g., u-boot-sunxi-with-spl.bin) is in u-boot/

  1. Exit nix-shell

exit Flashing U-Boot: This is board-specific and dangerous if done incorrectly. Consult your board's documentation. A common pattern (e.g., for Allwinner) but verify for your specific board: Bash

sudo dd if=u-boot-binary.bin of=/dev/sdX bs=1024 seek=8 # EXAMPLE ONLY! Verify offset and device! Optimizing Performance on ARM Tune your system for better responsiveness, especially on lower-power devices:

Nix

  1. configuration.nix

{

 # CPU frequency scaling governor (if supported)
 # 'ondemand' or 'schedutil' are common defaults. 'performance' uses max clock speed.
 powerManagement.cpuFreqGovernor = "ondemand";
 # IO scheduler tuning (improves SD card/eMMC performance)
 # mq-deadline is often a good choice for flash storage.
 services.udev.extraRules = 
   ACTION=="add|change", KERNEL=="mmcblk[0-9]|sd[a-z]", ATTR{queue/scheduler}="mq-deadline"
 ;
 # ZRAM Swap (compressed RAM swap - highly recommended over SD card swap)
 zramSwap = {
   enable = true;
   algorithm = "zstd"; # Fast compression
   # memoryPercent = 50; # Optional: Adjust percentage of RAM to use
 };
 # Ensure traditional swap files/partitions are disabled if using ZRAM primarily.
 # Use tmpfs for /tmp (reduces SD card writes)
 boot.tmpOnTmpfs = true;

} Security Hardening for ARM Devices Consider these options, especially for devices exposed to networks:

Nix

  1. configuration.nix

{

 # Example Kernel hardening parameters
 boot.kernelParams = [ "slab_nomerge" "init_on_alloc=1" "init_on_free=1" ];
 boot.kernel.sysctl = {
   "kernel.kptr_restrict" = "2";
   "kernel.dmesg_restrict" = "1";
   # Add other sysctl hardening options here
 };
 # Enable AppArmor Mandatory Access Control (generally lower overhead than SELinux)
 security.apparmor.enable = true;
 # Protect kernel image in memory
 security.protectKernelImage = true;
 # Basic firewall enabled previously is a good start. Configure rules as needed:
 # networking.firewall.allowedTCPPorts = [ 22 ]; # Example: Allow SSH
 # Consider enabling auditd for logging security events
 # security.audit.enable = true;
 # security.auditd.enable = true;

} Note: Always research the implications of hardening options. Some may affect performance or compatibility with specific hardware or software. Apply incrementally.

Wayland Support on ARM64 For graphical desktops, Wayland generally offers better performance on modern ARM64 devices:

Nix

  1. configuration.nix

{

 # Enable OpenGL drivers (essential)
 hardware.opengl = {
   enable = true;
   driSupport = true;
   # driSupport32Bit = true; # If running 32-bit apps via emulation
 };
 # Example for GNOME (Wayland by default)
 services.xserver = {
   enable = true;
   displayManager.gdm.enable = true;
   desktopManager.gnome.enable = true;
   # Optional: Explicitly prefer Wayland, though usually default
   # displayManager.gdm.wayland = true;
 };
 # Example for KDE Plasma (Choose Wayland session at login)
 # services.xserver = {
 #   enable = true;
 #   displayManager.sddm.enable = true;
 #   desktopManager.plasma5.enable = true;
 #   # Ensure sddm offers Wayland session (usually default)
 # };

} Raspberry Pi 4/5 Specific: Ensure appropriate GPU overlays are enabled in /boot/config.txt (NixOS modules might handle this, but verify). For RPi 5 Wayland, dtoverlay=vc4-kms-v3d-pi5 is often needed. Check nixos-hardware configs. Common ARM Device Troubleshooting UART Console Access: If the device doesn't boot fully or display video, connect a USB-to-Serial adapter to the board's UART pins. Add kernel parameters to enable console output (adjust device ttyS0/ttyAMA0 and speed 115200 based on board): Nix

  1. configuration.nix

boot.kernelParams = [

 "console=ttyS0,115200n8" # Example, check board specifics

]; Memory Constraints (Low RAM devices): Limit build resource usage: Nix

  1. configuration.nix

nix.settings = {

 cores = 1; # Limit parallel builds locally
 max-jobs = 1;

}; boot.tmp.cleanOnBoot = true; # Free up /tmp space on reboot (Use ZRAM swap, avoid heavy desktop environments). Network Issues (Wi-Fi/Bluetooth): Ensure necessary firmware is enabled: Nix

  1. configuration.nix

hardware.enableRedistributableFirmware = true; # For many common Wi-Fi/BT chips

  1. Some firmware might need specific enabling, e.g.:
  2. hardware.firmware = [ pkgs.wireless-regdb ];

Ensure networking.networkmanager.enable = true; for easier Wi-Fi management. Related Projects Mobile NixOS: Extends NixOS to run on mobile devices like the PinePhone. Provides modules for mobile-specific hardware and UI needs. See Mobile NixOS project. NixOS Hardware: A repository of hardware-specific configurations and workarounds for various devices, including many ARM boards. See NixOS/nixos-hardware. NixOS on ARM/QEMU: Instructions for running NixOS ARM builds within QEMU for development and testing. See the NixOS on ARM/QEMU wiki page.