NixOS on Btrfs with encrypted root

Posted on 2020-12-01

In this guide I will install NixOS on btrfs with an encrypted root partition.

Note: This guide is mostly just some notes for myself, proceed at your own risk!


You are expected to have a basic knowledge of both NixOS and the btrfs filesystem, and you will need an installation media if you are doing this on bare metal.

First, download the NixOS iso and flash it to your usb, where sdX is the name of the usb drive.

sudo dd if=/path/to/iso of=/dev/sdX bs=4M status=progress

Get started

Boot from the usb and setup your wifi connection

wpa_supplicant -B -i interface -c <(wpa_passphrase '<SSID>' '<password>')


The next step is to partition your drives, I will create three partitions.

Name Type Size
/dev/sdX1 EFI boot partition 512 MB
/dev/sdX2 Swap partition 8 GB
/dev/sdX3 Root partition with btrfs <rest>

Use your favourite partition program, I will use cfdisk. Run lsblk to make sure everything you didn’t mess things up.


We will encrypt the root partition (/dev/sdX3) using dm-crypt. First, format the partition and enter a passphrase which will be used for decrypting the partition.

cryptsetup luksFormat /dev/sdX3

Decrypt the partition and give it a name, I will call it crypted-nixos.

cryptsetup open /dev/sdX3 crypted-nixos


Format the partition and label them.

mkfs.vfat -F32 -n boot /dev/sdX1 # Boot
mkswap -L swap /dev/sdX2 # Swap
swapon /dev/sdX2 # Activate swap
mkfs.btrfs -L nixos /dev/mapper/crypted-nixos # Root

Mounting & Subvolumes

We now have one btrfs volume and we will have to create some subvolumes.

Name Mount point Purpose
@ / Root filesystem
@home /home Home directory, will be backed up

The home directory will backed up, everything else is either managed by nix or just temporary files. We will first mount our encrypted root partition and then create the subvolumes.

mount -t btfs /dev/mapper/crypted-nixos /mnt # Remember the device name?

btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home

umount /mnt

Once the subvolumes have been created, we will mount them with our desired options.

mount -o subvol=@,compress=lzo,noatime /dev/mapper/crypted-nixos /mnt

mkdir /mnt/home
mount -o subvol=@home,compress=lzo,noatime /dev/mapper/crypted-nixos /mnt/home

And don’t forget to mount the boot partition!

mkdir /mnt/boot
mount /dev/sdX1 /mnt/boot

We can run btrfs subvol list /mnt/ to list our subvolumes and make sure everything is correct.


Now we can install NixOS on the filesystem. First, generate a base config.

nixos-generate-config --root /mnt

Since we have encryption, we need to make sure that we have the following in our hardware-configuration.nix or configuration.nix.

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

  boot.supportedFilesystems = [ "btrfs" ];

  boot.initrd.luks.devices = {
    "crypted-nixos" = {
      device = "/dev/disk/by-uuid/<uuid>";

Replace crypted-nixos with the name of your device, and replace <uuid> with the uuid of /dev/sdX3. The rest of the config is left for you to configure yourself.

Go back to the shell and install the system.


If it all goes well, we should be able enter our dm-crypt passphrase and login as a user.


When your system works you probably want to make snapshots on a regular basis in case something goes wrong. I like to take snapshots every time my system starts up and shuts down, so that’s what we will configure in this guide.

We first want to create a script which will take snapshot for us. The following script is based on a script from the Gentoo wiki.

{ config, lib, pkgs, ... }:
  btrfsSnapshot = pkgs.writers.writeBashBin "btrfs-snapshot"
    NOW=$(date +"%Y-%m-%d_%H:%M:%S")

    if [ ! -e /mnt/backup/home ]; then
      mkdir -p /mnt/backup/home

    cd /
    ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot /home "/mnt/backup/home/home_''${NOW}"
  environment.systemPackages = [

Now we want to create a systemd service that runs this script on startup and shutdown.

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

{"btrfs-snapshot" = {
    description = "Create btrfs snapshot on startup and shutdown.";
    serviceConfig = rec {
      ExecStart = "${btrfsSnapshot}/bin/btrfs-snapshot";
      ExecStop = ExecStart;
      Type = "oneshot";
      RemainAfterExit = true;
    requiredBy = [ "" ];

We can also scrub our file system once every month.

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

  services.btrfs.autoScrub = {
    enable = true;
    fileSystems = [ "/" ];
    interval = "monthly";

Articles from blogs I follow...

Generated by openring

Outreachy 'guix git log' internship wrap-up

Magali Lemes joined Guix in December for a three-month internship with Outreachy . Magali implemented a guix git log command to browse the history of packaging changes, with mentoring from Simon Tournier and Gábor Boskovits. In this blog post, Magali…

via GNU Guix — Blog April 8, 2021

What should the next chat app look like?

As you’re surely aware, Signal has officially jumped the shark with the introduction of cryptocurrency to their chat app. Back in 2018, I wrote about my concerns with Signal, and those concerns were unfortunately validated by this week’s announcement. Moxie’…

via Drew DeVault's blog April 7, 2021

Uphold Marxism-Leninism-Maoism-Stallmanism!

Chairman Stallman has been under fire lately from the reactionary forces that have gathered mainly on the American propaganda machine called Twitter. Parties interested in the demise of the ideological advances of Free Software want to sabotage the movement,…

via brown121407 March 25, 2021