Nix & NixOS

This article contains tips & tricks for using NixOS.

Installing NixOS

This guide lays out how to install NixOS with an encrypted root and swap disk. The resulting system will have 2 physical partitions:

Physical partitions

First, determine if your machine supports UEFI (most modern PCs), or only has BIOS (e.g. my Thinkpad X201).

If it has UEFI, the below snippet creates a 512MiB UEFI boot partition, which has to be FAT32, and uses the rest of the disk for our cryptroot.

$ parted /dev/sda
> mklabel gpt
> mkpart ESP fat32 1MiB 512MiB
> set 1 boot on
> mkpart primary 512MiB 100%
> quit

For machines without UEFI, the procedure is similar, but needs to use BIOS and MBR formats.

$ parted /dev/sda
> mklabel msdos
> mkpart primary 1MiB 512MiB
> set 1 boot on
> mkpart primary 512MiB 100%
> quit

To set up LUKS disk encryption, first encrypt the second partition (/dev/sda2), then unlock it and map it at /dev/mapper/cryptroot:

$ cryptsetup luksFormat /dev/sda2
$ cryptsetup open /dev/sda2 cryptroot

Virtual Partitions

To split our LUKS-encrypted partition into two virtual partitions, we will use LVM to create a Physical Volume containing a Volume Group containing 2 Logical Volumes.

Create a Physical Volume (pv):

$ pvcreate /dev/mapper/cryptroot

Create a Volume Group (vg) on that pv:

$ vgcreate vg /dev/mapper/cryptroot

Create two Logical Volumes (lv) on that vg, one for swap and one for data:

$ lvcreate -L 8G -n swap vg
$ lvcreate -l '100%FREE' -n root vg

Formatting & Mounting

For UEFI, format the boot partition as FAT32:

$ mkfs.fat -F 32 -n boot /dev/sda1

For BIOS / MBR, format the boot partition as EXT4:

$ mkfs.ext4 -L boot /dev/sda1

For both, format / and the swap partition:

$ mkfs.ext4 -L root /dev/vg/root
$ mkswap -L swap /dev/vd/swap

Then mount them all:

$ mount /dev/vg/root /mnt
$ mkdir /mnt/boot
$ mount /dev/sda1 /mnt/boot
$ swapon /dev/vg/swap

Actually installing NixOS

We will need to make sure that our encrypted physical partition is unencrypted early in boot, so that the virtual partitions can be mounted.

Generate an initial configuration.nix:

$ nixos-generate-config --root /mnt

The file /mnt/etc/nixos/hardware-configuration.nix should reference the UUIDs for the physical /dev/sda1 and logical /dev/vg/root and /dev/vg/swap.

To mount the encrypted LVM partitions early in boot, we need to pass the UUID of the physical partition /dev/sda2 to initrd. This can be found with ls -l /dev/disk/by-uuid and seeing which UUID is pointing to /dev/sda2:

$ ls -l /dev/disk/by-uuid
... b2bacfda-0929-43ef-9f8f-c326c41d9126 -> ../../sda1
... 4e906a20-63fc-4aec-93de-8502f24daa91 -> ../../sda2
... 97650361-78bc-4026-962d-0774fc388d63 -> ../../dm-1
... fa099f4f-38b8-4ebc-914c-86b11598128d -> ../../dm-2

This value must then be

$ cat /mnt/etc/nixos/configuration.nix
...
boot.loader.grub.device = "/dev/sda";
boot.initrd.luks.devices.root = {
  device = "/dev/disk/by-uuid/4e906a20-63fc-4aec-93de-8502f24daa91";
  preLVM = true;  # we need to decrypt the physical partition before LVM mounts our logical partitions.
  allowDiscards = true;  # enables TRIM, optional.
};

Continue NixOS installation, rebooting after:

$ nixos-install
$ reboot

After rebooting, you will need to type your LUKS password, and it should boot normally from there on.