Additional Reading

This guide presumes the following

  • That your /boot mount corresponds to a distinct partition with /boot/efi being on your ESP (which itself, is a distinct partition independent of /boot)
  • That your root filesystem uses BTRFS (multiple guides exist on the internet if you use EXT4)
  • That you do not use the Logical Volume Manager and are just dealing with plain BTRFS
  • You are willing to deal with some system downtime and that you are booting and following this guide from a Debian live USB with an internet connection
  • That /dev/sdX1 is your ESP, /dev/sdX2 is your root partition, /dev/sdX4 is your /boot drive (it’s very likely that it’s not, I’m just mentioning this so that you change it instead of possibly doing destructive actions to a completely unrelated disk)
  • You have a backup… on a distinct physical disk if this blows up in your face or you have a power outage or thermonuclear warfare ensues
  • That your computer is modern enough that it doesn’t have to deal with USB keyboard shenanigans as this guide does not account for it

Encrypting your root partition

Mounting and resizing your BTRFS filesystem (not partition, filesystem)

Did you know… You can resize a filesystem without resizing the partition it lies on! Turns out, they are two distinct things. For this guide, as we need to introduce a LUKS header, we need to shrink our drive’s filesystem (while maintaining the partition size) before we get going.

Let’s first create a folder that will contain our mounted root directory

# mkdir /mnt/btrfs

Then mount our BTRFS root partition and query its available size

# mount /dev/sdX1 /mnt/btrfs
# btrfs filesystem usage -b /mnt/btrfs

btrfs filesystem usage -b /mnt/btrfs should return information to the tune of

[...]
    Used:                              77960871936
    Free (estimated):                 136431190016      (min: 136431190016)
    Free (statfs, df):                136430141440
    Data ratio:                               1.00
    Metadata ratio:                           1.00
[...]

Let’s take the Free (statfs, df) value of 136430141440 for my drive (naturally, yours will differ) and multiply it by 0.9 (use a calculator or better yet, a search engine so you can just Ctrl+C, Ctrl+V that) and then you’ll get 122787127296.

Make sure that the difference at least provides you with 128M of buffer space to play with. Now let’s resize our BTRFS filesystem by running.

# btrfs filesystem resize -122787127296 /mnt/btrfs # The minus sign indicates that this is a shrink operation

Now that we have resized our filesystem, it’s time to encrypt the partition.

Unmounting and encrypting your filesystem using LUKS2

First, we must unmount our BTRFS filesystem.

# umount /mnt/btrfs

Then we can encrypt the filesystem using cryptsetup and ask it to allocate 128M for our LUKS header.

# cryptsetup reencrypt --encrypt --reduce-device-size 128M /dev/sdX1 # You need to set your password here

Once that succeeds, we will now mount our freshly encrypted LUKS partition.

Mounting your encrypted filesystem and resizing it again

Our new LUKS parition will be mapped to the name cryptroot (you can change this to anything you want but the rest of the guide operates on the presumption that you’re naming it cryptroot). Let’s mount it.

# cryptsetup luksOpen /dev/sdX1 cryptroot # You will be prompted your password

Once we have done that, our unlocked container is now mapped to /dev/mapper/cryptroot so now let’s mount the BTRFS filesystem it contains.

# mount /dev/mapper/cryptroot /mnt/btrfs

Once we have achieved that, let’s reclaim the space and undo the shrinking operation from last time.

# btrfs filesystem resize max /mnt/btrfs

Good news! You now have an encrypted root partition. Bad news, you cannot boot from it.. yet.

Setting up our chroot environment

We will be setting up an environment such that we re-define / (root) to be the root directory of our filesystem instead of the root directory of our live environment (hence, we’re changing our root directory… so chroot). We will use the chroot command to do that but before we do, we have to do some setup.

Have two terminal tabs, one for the chroot'ed environment and one for your live installation. Let’s go to the live installation, first.

Let’s start by mounting our /boot and /boot/efi partitions for our chrooted environment to eventually access

P.S. All commands inside the chroot will be prefixed with a % to distinguish them while commands in the live environment are prefixed with #

# mount /dev/sdX4 /mnt/btrfs/boot
# mount /dev/sdX1 /mnt/btrfs/boot/efi

Now we need to give our chroot the ability to access block devices. To do so, we will need to bind mount /dev/

# mount -B /dev /mnt/btrfs/dev

Now go to the chroot'ed tab (if you don’t have one, you can open a new tab and type in chroot /mnt/btrfs to get into a chrooted environment) and have the chrooted environment mount /proc and /sys filesystems.

% mount --types=proc proc /proc
% mount --types=sysfs sys /sys

Now return to the live environment tab and mount the directory that contains your NVRAM variables (important for when you update GRUB) so that your chroot'ed environment can access them

# mount -B /sys/firmware/efi/efivars /mnt/btrfs/sys/firmware/efi/efivars

Modifying our operating system configuration files

Installing dependencies

We need to install cryptsetup-initramfs package into the chroot so that the bootloader and bootstrapping process can read and understand encrypted filesystems. But running apt won’t work because our chroot doesn’t know how to resolve domain names, which our package managers rely on, so to fix that we must first go to our live environment and run…

# cp /etc/resolv.conf /mnt/btrfs/etc/resolv.conf

Once we’ve done that, now we can install the package within our chroot!

% apt update && apt install cryptsetup-initramfs -y

Telling our operating system that root is mounted from an encrypted partition

Now that we’ve setup our chroot, we can use it to modify our existing installation, its boot partition and the EFI System Partition (as we mounted them in our earlier steps).

First, let’s tell our operating system that there is an encrypted filesystem in the first place by modifying /etc/crypttab. Before we do that, we need to know the UUID of the LUKS partition (not the underlying BTRFS partition) and to do that, we will run lsblk -f, which will give you an output similar to

[...]
sdX
├─sdX1        vfat        FAT32           AAAA-AAAA                            1017.9M     0% /mnt/btrfs/boot/efi
├─sdX2        crypto_LUKS 2               ffffffff-ffff-ffff-ffff-ffffffffffff
│ └─cryptroot btrfs                       f0f0f0f0-f0f0-f0f0-f0f0-f0f0f0f0f0f0    127G    36% /mnt/btrfs/
├─sdX3        btrfs       Home            aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa  163.4G    38% /mnt/btrfs/home
└─sdX4        vfat        FAT32           FFFF-FFFF                               682M    33% /mnt/btrfs/boot
[...]

We’re interested in the UUID of crypto_LUKS, not BTRFS and so we’ll take ffffffff-ffff-ffff-ffff-ffffffffffff (yours will naturally, vary)

Then open up /etc/crypttab with an editor of your choice and ensure that it looks something like this

# <name>               <device>                                     <password>     <options>
cryptroot              UUID=ffffffff-ffff-ffff-ffff-ffffffffffff     none          luks

Done? Not quite. Now we need to modify /etc/fstab and tell it that we’re no longer booting off an unencrypted BTRFS partition but to a map of an encrypted partition…

Once you open /etc/fstab, you’ll probably have something akin to this…

[...]
# <file system>                           <mount point>  <type>  <options>        <dump>  <pass>
UUID=f0f0f0f0-f0f0-f0f0-f0f0-f0f0f0f0f0f0 /               btrfs   defaults,noatime 0      1
[..]

You should change it in a way such that it results in looking like this..

[...]
# <file system>                           <mount point>  <type>  <options>        <dump>  <pass>
/dev/mapper/cryptroot                     /              btrfs   defaults,noatime 0       1
[...]

Telling the bootloader (GRUB) that we’re booting off an encrypted partition

Now that we’ve changed our /etc/crypttab and /etc/fstab (these files are read by the operating system in this order), now it’s time to tell GRUB all about it. Just remember your crypto_LUKS UUID (ffffffff-ffff-ffff-ffff-ffffffffffff) somewhere.

Open up /etc/default/grub with your preferred text editor and ensure these lines are present in them

# Setting up GRUB (/etc/default/grub)
GRUB_PRELOAD_MODULES="cryptodisk luks"
GRUB_ENABLE_CRYPTODISK=y

Then find the GRUB_CMDLINE_LINUX_DEFAULT variable and ensure that cryptdevice=UUID=ffffffff-ffff-ffff-ffff-ffffffffffff root=/dev/mapper/cryptroot is appended to whatever may or may not be there.

Mine for example, ends up looking like…

[...]
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash cryptdevice=UUID=ffffffff-ffff-ffff-ffff-ffffffffffff root=/dev/mapper/cryptroot"
[...]

As long cryptdevice detection by UUID and root mapping by crypttab name is in the variable, you’re good (hint: the delimiter between each instruction is a space)

Now we need these changes to be reflected.

% grub-install /dev/sdX         # Presuming /dev/sdX is the destination drive, do not append numbers
% update-initramfs -c -k all    # Updates the ramdisk...
% update-grub2                  # Remember to add encrypted root to /etc/crypttab and /dev/mapper/cryptroot is in fstab

Hopefully, we’re now done with what we’ve needed to do, so now let’s do a cleanup because cleanup good (you can close the chroot, we’re done with it)

# sync  # Ensure everything we've done is flushed to disk
# umount /mnt/btrfs/sys/firmware/efi/efivars
# umount /mnt/btrfs/sys
# umount /mnt/btrfs/proc
# umount /mnt/btrfs/boot/efi
# umount /mnt/btrfs/boot
# umount /mnt/btrfs/dev
# umount /mnt/btrfs
# sync  # For good luck

Reboot, fingers crossed and hope things work. If they don’t, then Google is your friend and hope you have a backup!

Additional Observations

Due to a bug in GRUB, when I followed other guides which recommended to additionally add usb usb_keyboard ehci ohci uhci to my GRUB_PRELOAD_MODULES, it bricked my bootloader by breaking hard drive detection.

I remember reading some forum post at 1AM where the same thing was talked about but I can’t find it. It is quite possible you’ll need to read additional guides that talk about enabling USB keyboard support in GRUB but I’ve omitted it from my guide as my computer didn’t need it and it bricked my bootloader (these guides come from stuff that I work on during off hours and figure that it’s neat to write about it by going through my command history and retracing my steps).