~yoctocell/yoctocell.xyz

yoctocell.xyz/src/posts/nixos-on-btrfs-with-encrypted-root.org -rw-r--r-- 5.5 KiB
46c74072Xinglu Chen templates: footer: Fix typo 2 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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#+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