While btrfs may be relatively “new” in regards to file systems, it is receiving widespread adoption, being included as the default FS in many distros. They is because it provides many advantages when compared to the traditional luks on lvm encrypted linux install:
- Subvolume Snapshots: btrfs is a copy-on-write FS (CoW) meaning changes to an individual file result in a new file being written. This means that each subvolume can be snapshotted, where a complete version of every file is captured at a moment in time. This enables simple backup and rollback in case of failure.
- Automatic Compression: btrfs subvolumes can store files with dynamic compression. This is extremely configurable across subvolumes with tradeoffs is speed and compression ratio to support the variance in subvolume usage.
- Subvolume Resizing: Files are tracked using simple pointers (actually quite complex, but I know very little and can explain even less). This means that unlike traditional disk partitions, which are defined as a collection of disk blocks, data on a single subvolume may span the entire disk and subvolumes contents are tracked with the file descriptors. This means changing subvolume sizes does not mean physically redefining disk partitions but is rather handled quickly and efficiently in metadata.
- Many More: But this is not a post on the merits of btrfs.
The problem is that I run debian stable (current version 11). The beauty (and the curse) of this distribution choice is that things move a little slower. As such, the debian installer does not currently support installing btrfs with subvolumes.
Fortunately, there is a fantastic article by Jake Bauer describing how this can be done in debian 10. Unfortunately, the instructions still configure LUKS on LVM with the btrfs subvolumes in an LVM volume group rather than directly within the LUKS crypt. Therefore, I’ve decided to write up this brief tutorial to provide the later.
Begin the Installation
Push the USB in, and being the installing by choosing Advanced options > Expert install
. This is important because it enables us to manually configure btrfs subvolumes later.
Partition Devices
In the partition scheme definition choose Manual
partitioning.
We need to create 2 partitions:
- EFI partition: I set this to 512MB and the installer should default to vfat and automatically handle
/boot/efi
mount. - boot partition: This can be 512MB as well and should set the
Use as:
field toext2
and set the mount point to/boot
.
Then use the Configure encrypted volumes
option to create an encrypted LUKS partition with the remaining space. On this LUKS encrypted partition (mine is nvme0n1p3_crypt
) set the Use as:
field to btrfs journaling file system
and the mount point /
.
Finish partitioning and write changes to disk
But what about a swapspace?
I typically do not install with swapspace. My machine is equipped with more than adequate RAM and therefore it is only useful for hibernation, which I seldom use. If you want a swapspace, there are a variety of options:
- As a separate disk partition.
- As an individual btrfs subvolume.
- As a btrfs swapfile.
Manually Create and Mount btrfs Subvolumes
One the partitions are written, and BEFORE continuing the installation, we need to manually create and mount the btrfs subvolumes.
There are two trains of though for organizing btrfs subvolumes:
- hierarchical: subvolumes are defined within other subvolumes.
- flat: subvolumes are mounted within other subvolumes but are define externally.
I prefer a flat layout, probably because it results in more clearly defined partitions. If you would rather install with a hierarchical system, you can probably figure out the requisite changes.
Begin by pressing Ctrl+Alt+F2
to drop into a shell and press Enter
to activate it.
Use the df
command to view the current mounted partitions. There should be three important mounts:
- The luks encrypted btrfs root subvolume mounted to
/target
- mine is the device/dev/mapper/nvme0n1p3_crypt
. - The boot partition mounted to
/target/boot
- mine is the device/dev/nvme0n1p2
. - The EFI partition mounted to
/target/boot/efi
- mine is the device/dev/nvme0n1p1
.
We need to umount the partitions in reverse order:
~ # umount /target/boot/efi
~ # umount /target/boot
~ # umount /target
Then we mount our existing root subvolume to /mnt
.
~ # mount /dev/mapper/nvme0n1p3_crypt /mnt
Create new subvolumes. I have chosen separate for /root
, /home
, and /var
. /snapshots
is used to store btrfs snapshots. You can easily update this to your preference.
~ # btrfs subvolume create @
~ # btrfs subvolume create @home
~ # btrfs subvolume create @var
~ # btrfs subvolume create @snapshots
And mount them underneath the installation directory /target
. There are tons of different mount configuration options, these are a sane default selection.
~ # mount -o noatime,compress=lzo,space_cache,subvol=@ /dev/mapper/nvme0n1p3_crypt /target
~ # mkdir /target/home
~ # mount -o noatime,compress=lzo,space_cache,subvol=@home /dev/mapper/nvme0n1p3_crypt /target/home
~ # mkdir /target/snapshots
~ # mount -o noatime,compress=lzo,space_cache,subvol=@snapshots /dev/mapper/nvme0n1p3_crypt /target/snapshots
~ # mkdir /target/var
~ # mount -o noatime,compress=lzo,space_cache,subvol=@var /dev/mapper/nvme0n1p3_crypt /target/var
Remount the /boot
and /boot/efi
partitions.
~ # mkdir /target/boot
~ # mount /dev/nvme0n1p2 /target/boot
~ # mount /dev/nvme0n1p1 /target/boot/efi
Copy over the /etc
metadata.
~ # mkdir /target/etc
~ # cp /mnt/etc/fstab /target/etc
~ # cp /mnt/etc/crypttab /target/etc/crypttab
Update the fstab file (now located at /target/etc/fstab
) to include our new btrfs subvolume mounts. It should end up looking something like the example below:
# <file system> <mount point> <type> <options> <dump> <pass>
#/dev/mapper/nvme0n1p3_crypt / btrfs defaults,subvol=@rootfs 0 0
# /boot was on /dev/nvme0n1p2 during installation
UUID=f434d69d-c351-498d-bb6c-0b78d44754dc /boot ext2 defaults 0 2
# /boot/efi was on /dev/nvme0n1p1 during installation
UUID=BF50-85A0 /boot/efi vfat umask=0077 0 1
# btrfs subvolumes mounted manually during installation
/dev/mapper/nvme0n1p3_crypt / btrfs noatime,compress=lzo,space_cache,subvol=@ 0 0
/dev/mapper/nvme0n1p3_crypt /home btrfs noatime,compress=lzo,space_cache,subvol=@home 0 0
/dev/mapper/nvme0n1p3_crypt /snapshots btrfs noatime,compress=lzo,space_cache,subvol=@snapshots 0 0
/dev/mapper/nvme0n1p3_crypt /var btrfs noatime,compress=lzo,space_cache,subvol=@var 0 0
And finally cleanup the btrfs root, otherwise these directories will remain in the final installation.
~ # rm -r /mnt/boot /mnt/etc /mnt/media
~ # umount /mnt
Once this is done you can exit out of the terminal with Ctrl+D
and return to the installation with Ctrl+Alt+F1
.
Complete the Installation
The remainder of the installation can be completed as usual. Reboot into your brand new debian 11 installation with LUKS encrypted btrfs subvolumes!
12 day(s) offloaded in the 100DaysToOffload challenge.