---
title: "Nixos on Raspberry Pi 4"
date: 2022-04-07T12:20:02-05:00
draft: false
tags:
  - Nix
  - NixOS
---
So I've been playing around with NixOS on a Raspberry Pi 4 that I have at the house. NixOS seems like a great idea,
but getting it onto the Raspberry Pi 4 is something of a beast of a process. So I wanted to document here how I did
it. Most of the process is the normal NixOS installation process, with a few tweaks at the very end.

# My Pi's Case is a Challenge

Rather than having a plain Raspberry Pi 4 and writing the SD image provided by the NixOS team to that image, I have
my Pi in an [Argon One m.2](some link here) case. That case allows me to mount an m.2 SSD to an RPi4 B device over
USB3. They're pretty slick cases, decent quality, include full size HDMI ports and basic power management, and still
allow GPIO header splitouts if you need them for your application. If you are looking for a handy little case that
is metal, well built, functions as a heat sync, includes a tiny fan, and gives you the SSD USB3 split out, then I
suggest you take a look at this case. They also have a version that does not have the SSD, but still gives you the
port split out and is the same well built metal top enclosure.

One downfall of the case is that, when closed, it does not leave the SD card slot accessible. You can load an SD card
in before you put the Pi into the case if you plan to always boot off one, but I wanted the significantly better speed
that the SSD over USB3 can give compared to a plain SD card. So, before I loaded the Pi into the case I used the
SD card slot to update the Pi firmware (my 4s are pretty old) and set it to default boot from USB by default.

I am going to operate under the assumption you have your Pi set to boot off of USB and already have a chosen device
plugged in to the system.

# NixOS Boot

NixOS provides two main ways to install. There is a bootable ISO file, and for machines like the RPi4 there is a
pre-built SD card image. While it's maybe possible to get the Aarch64 ISO to boot, I have not spent time working on
that. I opted for a manual install based on the SD card image. But I did not use an SD card.

## Get the SD Image

Get the latest version of the SD image. At the time of writing the latest release of NixOS is 21.11, so the latest
versions of the images can be found [in Hydra](https://hydra.nixos.org/jobset/nixos/release-21.11-aarch64). From
that page select the "Jobs" tab. Search the page for "sd\_image". I opted for the item called "nixos.sd\_image.aarch64-linux".
There is also one that is called "sd\_image\_new\_kernel". I haven't tried it, so I cannot tell you if it works.

Use your favorite tool to burn the image to a regular USB flash drive. I have used the Raspberry Pi Imager program
as well as `dd` from the command line in Linux. There are other tools, but choose your favorite one to write it
to a Flash Drive.

With the RPi4 turned off, insert the prepared Flash Drive to the RPi4's USB port. I have one of the USB3 ports open,
so that's the one I selected. If necessary, select this drive. In my case, this Flash Drive ends up as the default
option.

## Parition the SSD

The SD Image will boot you to a terminal and auto log in as the "nixos" user. Now you need to partition the drive.
You should have access to the `lsblk` tool that can list the drives. In my case the flash drive is `/dev/sdb` and
the SSD is `/dev/sda`. If you are on a different system, adjust these commands appropriately. I started by wiping
the SSD with `wipefs`.

```bash
sudo wipefs -f /dev/sda
```

Now you need to partition the SSD card. So let's enter our partition utility

```bash
sudo fdisk /dev/sda
```

Create partition 1 starting from sector 2048, with size 500M.

```
n
p
1
2048
+500M
```

Create other partitions the way you want them laid out. I create one large root partition that takes up from 500M
to within 8GB of the end of the drive. The last 8GB I reserve for swap. So these commands create those two
partitions.

```
n
p
2
<enter>
-8G

n
p
3
<enter>
<enter>
```

Now set the partition types

```
t
1
0b
t
3
82
```

0b is the code for W95 FAT32 and 82 is the type for Linux Swap. Now, save the partition table and exit the
program with command `w`. Be sure the filesystems are synced.

```bash
sudo sync
```

## Format the drives

Format the partitions you created. These are the ones I use:

```bash
sudo mkfs.vfat /dev/sda1
sudo mkfs.ext4 /dev/sda2
sudo mkswap /dev/sda3
sudo swapon /dev/sda3
```

Obviously you can use whatever format you want for your Linux partitions and you might have skipped a
swap partition. But that first partition needs to be a vfat partition to store the UEFI code.

## Mount the drive

Now, create the mountpoint where the target system will be installed.

```bash
sudo mkdir -p /mnt
sudo mount /dev/sda2 /mnt
sudo mkdir -p /mnt/boot
sudo mount /dev/sda1 /mnt/boot
```

## Generate and Customize Config

If you have your own way to fetch NixOS Configuration files, go ahead and fetch those to /mnt/etc/nixos.
If you are new to NixOS, then just skip that bit.

Generate the base configuration:

```bash
sudo nixos-generate-config --root /mnt
```

The general process of configuration and is beyond this, but be sure you have at least a text editor of
some kind in your installation!  Now go to /mnt/etc/nixos/ and edit the configuration to your heart's desire.
The following settings are great for a Raspberry Pi 4:

```
{
	boot = {
		# The Linux kernel version
		kernelPackages = pkgs.linuxPackages_rpi4;
		# Options to enable serial console and more
		kernelParams = [
			"8250.nr_uarts=1"
			"console=tyAMA0,115200"
			"console=tty1"
			"cma=128M"
		];

		# The bootloader
		loader = {
			raspberryPi = {
				enable = true;
				version = 4;
			};

			# Use extlinux, whereas the NixOS default is Grub
			grub.enable = false;

			# Enables the generation of /boot/extlinux/extlinux.conf
			generic-extlinux-compatible.enable = true;
		};
	};

	environment.systemPackages = with pkgs; [
		raspberrypifw
	];
}
```

## Install

Normally in NixOS you would now run the basic installer `sudo nixos-install --root /mnt`. However,
the SD image does not have any of the NixOS channels installed and it lacks the space necessary to
sync them in the default edition. So now we have to run the command in a slightly different way.

```bash
sudo nixos-install --root /mnt -I https://channels.nixos.org/nixos-21.11-aarch64/nixexprs.tar.xz
```

## Copy the firmware

Raspberry Pis require special firmware. By default this does not get installed into the `/boot`
partition where UEFI needs to find it. However, it is in the Flash drive that you are already running.
So let's copy it over. In my system, remember that the Flash drive is `/dev/sdb`. So for me this
process looks like this

```bash
sudo mkdir -p /firmware
sudo mount /dev/sdb1 /firmware
sudo cp -r /firmware/* /mnt/boot
```

This should allow you to boot the system off of the SSD. Now power off the system, remove the
Flash drive, and boot.

# Enjoy

Reboot into NixOS, login as root with the password you created during install, and set any password
for users you may have created in your configuration.
