Nix & NixOS: Installation with encrypted root

My NixOS Desktop

For my desktop, I set up NixOS with an encrypted root partition. The steps taken were not obvious to me from the official documentation, so I’ll be documenting them here for future reference. The setup described uses LVM inside a luks-encrypted root partition and a unencrypted /boot partition for EFI.

Installation media

NixOS provides two .iso images you can boot for the installation: A full-fledged graphical installer and a minimal image without a desktop environment, you can use either of them for the following. I went with the graphical image and did the following steps in the provided terminal emulator, but the procedure in a TTY should be identical.

To create a bootable usb-stick, do as you would for any other Linux distribution. Lazy people seem to like balena etcher, I went with the traditional command-line approach.

Fun fact: Did you know that you don’t need the “standard” dd bs=4M if=path/to/nixos.iso of=/dev/sdX status=progress oflag=sync that all wikis seem to love? Using cat is more than enough:

cat path/to/nixos.iso > /dev/sdX

In either case, triple-check that your device (here: /dev/sdX) is correct! I like to use lsblk to list devices.

Smashing keys get into BIOS

In case your stick boots right up, you can skip this paragraph. While it should boot, I’ve yet to encounter a single time this works on the first try. Once you have found the key to get into the BIOS of your motherboard (by smashing f1, f2, f10, f12, Delete, Enter until you get it right), here are a few common settings to check that have caused me trouble in the past. In particular, I usually disable legacy boot completely in favor of EFI, so I can be sure it won’t randomly switch to legacy mode.

  • Check boot order
  • Disable Secure Boot
  • Disable USB legacy boot
  • Enable Launch CSM

Partitioning

Partitioning in NixOS is manual and mostly the same as you would do in Arch or any other “minimal” distribution. You can use gparted if you decided to boot the graphical installer, but I find the process simpler with good-old gdisk.

We will be creating two partitions:

  • EFI partition (500M)
  • Encrypted physical volume for LVM (remaining space)

Furthermore, LVM will be used inside the encrypted physical volume and I will be adding 8G of swap. For the thoroughly-paranoid this has the added benefit, that the swap partition will also be encrypted.

Assuming the drive you want to install to is /dev/sda, run gdisk /dev/sda and create the partitions:

  • o : Create empty gpt partition table)
  • n : Add partition, first sector: default, last sector: +500M, type ef00 EFI
  • n : Add partition, remaining space, type 8300 Linux LVM
  • w : Write partition table and exit

We can now set up the encrypted LUKS partition and open it using cryptsetup

$ cryptsetup luksFormat /dev/sda2
$ cryptsetup luksOpen /dev/sda2 enc-pv

We create two logical volumes, a 8 GB swap partition and the rest will be our root file system

$ pvcreate /dev/mapper/enc-pv
$ vgcreate vg /dev/mapper/enc-pv
$ lvcreate -L 8G -n swap vg
$ lvcreate -l '100%FREE' -n root vg

Format the partitions:

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

Installing NixOS

The partitions just created have to be mounted, e.g. to /mnt so we can install NixOS on them. At this point activating the swap (if you created one) is a good idea. The /boot partion is mounted in a new folder /mnt/boot inside the root partition.

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

If you already have a configuration file for your system, you can place it now in /etc/nixos/configuration.nix. You can also let NixOS generate a working template for you and modify it to your liking.

$ nixos-generate-config --root /mnt

The command above will set everything up for you in /etc/nixos/ crating a configuration.nix and a hardware.nix file for you. In most cases you will want to make changes, just use any text-editor and open configuration.nix. There are a few options you will have to change to make your drive bootable, since it has to be decrypted.

This setup is tested with GRUB2. You can use any boot-loader that supports luks, but the following options should give you a working system. Notice that we use version 2 of grub and set the device to nodev. Cleaning up the /tmp dir is not really necessary, but I like to have it deleted on boot so nothing gets left behind.

# Use the Grub2 as bootloader.
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.device = "nodev";
boot.loader.grub.efiSupport = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.cleanTmpDir = true;

Next up: Decryption and LVM. You need to tell nix how to handle your drive setup. To get the UUID of your drive, run blkid on it

$ blkid /dev/sda2
/dev/sda2: UUID="/dev/disk/by-uuid/f4aaaf6d-4eb3-4a2d-a35e-f8e780ac0110" ...

Add the correct UUID and your config should look something like this:

boot.initrd.luks.devices = {
  root = {
    # Get UUID from blkid /dev/sda2
    device = "/dev/disk/by-uuid/f4aaaf6d-4eb3-4a2d-a35e-f8e780ac0110";
    preLVM = true;
    allowDiscards = true;
  };
};

That’s all! From here, you can modify your config like normally and include any services, accounts, pkgs, configs that you want. The procedure from here on is the same as with a non-encrypted drive. When you’re happy with the configuration, install NixOS and reboot into your new system.

$ nixos-install
$ reboot

Troubleshooting

Still here? Well, I guess something went wrong. If for whatever reason the system doesn’t boot, we can go back to the installation environment by booting from the installation media and remounting all partitions:

$ cryptsetup luksOpen /dev/sda2 enc-pv
$ lvchange -a y /dev/vg/swap
$ lvchange -a y /dev/vg/root
$ mount /dev/vg/root /mnt
$ mount /dev/sda1 /mnt/boot
$ swapon /dev/vg/swap

Fix it and try again until it works ;)

comments powered by Disqus