~yoctocell/yoctocell.xyz

ref: a1956e161482bc3b29e5a6bfb144073592202fd5 yoctocell.xyz/src/posts/nixos-on-btrfs-with-encrypted-root.org -rw-r--r-- 5.5 KiB
a1956e16Xinglu Chen Log.hs: Add function to handle parser errors 8 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#+TITLE: NixOS on Btrfs with encrypted root
#+DATE: 2020-12-01
#+AUTHOR: yoctocell

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!

** Prerequisites
You are expected to have a basic knowledge of both [[https://nixos.org][NixOS]] and the [[https://btrfs.wiki.kernel.org/index.php/Main_Page][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.

#+begin_src sh
sudo dd if=/path/to/iso of=/dev/sdX bs=4M status=progress
#+end_src

** Get started
Boot from the usb and setup your wifi connection

#+begin_src sh
wpa_supplicant -B -i interface -c <(wpa_passphrase '<SSID>' '<password>')
#+end_src

** Partitioning
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.

** Encryption
We will encrypt the root partition (=/dev/sdX3=) using [[https://gitlab.com/cryptsetup/cryptsetup/-/wikis/DMCrypt][dm-crypt]]. First, format the partition and enter a passphrase which will be used for decrypting the partition.

#+begin_src sh
cryptsetup luksFormat /dev/sdX3
#+end_src

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

#+begin_src sh
cryptsetup open /dev/sdX3 crypted-nixos
#+end_src

** Formatting
Format the partition and label them.

#+begin_src sh
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
#+end_src

** 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.

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

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

umount /mnt
#+end_src

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

#+begin_src sh
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
#+end_src

And don't forget to mount the boot partition!

#+begin_src sh
mkdir /mnt/boot
mount /dev/sdX1 /mnt/boot
#+end_src

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

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

#+begin_src sh
nixos-generate-config --root /mnt
#+end_src

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

#+begin_src nix
{ config, lib, pkgs, ... }:

{
  boot.supportedFilesystems = [ "btrfs" ];

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

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.

#+begin_src sh
nixos-install
poweroff
#+end_src

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

** Post-installation
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 [[https://wiki.gentoo.org/wiki/Btrfs#Snapshots][Gentoo wiki]].

#+begin_src nix
{ config, lib, pkgs, ... }:
let
  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
    fi
 
    cd /
    ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot /home "/mnt/backup/home/home_''${NOW}"
    '';
in
{
  environment.systemPackages = [
    btrfsSnapshot
  ];
}
#+end_src

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

#+begin_src nix
{ config, lib, pkgs, ... }:

{
  systemd.services."btrfs-snapshot" = {
    description = "Create btrfs snapshot on startup and shutdown.";
    serviceConfig = rec {
      ExecStart = "${btrfsSnapshot}/bin/btrfs-snapshot";
      ExecStop = ExecStart;
      Type = "oneshot";
      RemainAfterExit = true;
    };
    requiredBy = [ "multi-user.target" ];
  };
}
#+end_src

We can also scrub our file system once every month.

#+begin_src nix
{ config, lib, pkgs, ... }:

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