Ubuntu Desktop 20.04 with btrfs-luks full disk encryption
If you have followed me here, you know I am a big fan of BTRFS and luks based full disk encryption. I used to use Arch Linux in the past, however recently I have started using Ubuntu LTS as main OS mainly for simplicity and easy availability of numerous tricks online!
The main reason I want to to take this little complex route of installation than simple easy way that Ubuntu provides:
- A luks-based full disk encryption for data safety, specially since I work a lot with medical data!
- An un-encrypted EFI partition for the GRUB bootloader
- a btrfs-inside-luks partition for the root filesystem (including /boot) containing a subvolume
/and a subvolume
/homewith only one passphrase prompt from GRUB!
- automatic system snapshots and easy rollback similar to
This tutorial is made with Ubuntu 20.04 Focal Fossa copied to an installation media (usually a USB Flash device but may be a DVD or the ISO file attached to a virtual machine hypervisor). This has been adapted from this Blog.
Since most modern PCs have UEFI, I will cover only the UEFI installation. So, boot the installation
medium in UEFI mode, choose your language and click
Try Ubuntu. Once the Live Desktop environment
has started we need to use a Terminal shell command-line to issue a series of commands to prepare
the target device before executing the installer itself.
Now, open a terminal (CTRL+ALT+T) and run the following command:
to detect whether we are in UEFI mode. Now switch to an interactive root session:
You might find maximizing the terminal window is helpful for working with the command-line. Do not close this terminal window during the whole installation process until we are finished with everything.
First find out the name of your drive. For me the installation target device is called
We'll now create the following partition layout on
- a 512 MiB FAT32 EFI partition for the GRUB bootloader
- a 4 GiB partition for encrypted swap use
- a luks1 encrypted partition which will be our root btrfs filesystem
/bootwill reside on the encrypted luks1 partition. The GRUB bootloader is able to decrypt
luks1at boot time. Alternatively, you could create an encrypted
luks2encrypted partition for the root filesystem.
- With btrfs I do not need any other partitions for e.g.
/home, as we will use subvolumes instead.
parted for this (feel free to use
Do not set names or flags, as in my experience the Ubiquity installer has some problems with that.
The default luks (Linux Unified Key Setup) format used by the cryptsetup tool has changed since the
release of Ubuntu 18.04 Bionic. 18.04 used version 1 (
luks1) but more recent Ubuntu releases
default to version 2 (
luks2) and check that
/boot is not located inside an encrypted partition.
GRUB is able to decrypt luks version 1 at boot time, but Ubiquity does not allow this by default.
Note that if you want to use luks version 2 you should create an encrypted
using version 1, whereas the root filesystem can then be formatted using version 2.
Either way, we need to prepare the
luks1 partition or else GRUB will not be able to unlock the
encrypted device. Note that most Linux distributions also default to version 1 if you do a full
disk encryption (e.g. Manjaro Architect).
Use a very good password here. Now map the encrypted partition to a device called
which will be our root filesystem:
Create a filesystem for the EFI System partition. If there was e.g. an NTFS filesystem at the beginning of the drive, the Ubiquity installer will be unable to mount the filesystem otherwise.
We need to pre-format
cryptdata because, in my experience, the Ubiquity installer messes
something up and complains about devices with the same name being mounted twice.
cryptdata is our root partition which we'll use for the root filesystem.
Unfortunately, the Ubiquity installer does not set good mount options for btrfs on SSD or NVME drives, so you should change this for optimized performance and durability. I have found that there is some general agreement to use the following mount options:
ssd: use SSD specific options for optimal use on SSD and NVME
noatime: prevent frequent disk writes by instructing the Linux kernel not to store the last access time of files and folders
space_cache: allows btrfs to store free space cache on the disk to make caching of a block group much quicker
commit=120: time interval in which data is written to the filesystem (value of 120 is taken from Manjaro)
compress=zstd: allows to specify the compression algorithm which we want to use. btrfs provides
zlibcompression algorithms. Based on some Phoronix test cases,
zstdseems to be the better performing candidate.
- Lastly the pass flag for
fstabis useless for btrfs and should be set to 0.
We need to change two configuration files:
So let's use an editor to change the following:
Now let's run the installation process, but without installing the bootloader, as we want to
/boot on an encrypted partition which is actually not allowed by Ubiquity.
So we need to run the installer with:
Choose the installation language, keyboard layout, Normal or Minimal installation, check the boxes of the Other options according to your needs. In the "Installation type" options choose "Something Else" and the manual partitioner will start:
/dev/nvme0n1p1, press the
Use as'EFI System Partition'.
/dev/nvme0n1p2, press the
Use as'swap area' to create a swap partition. We will encrypt this partition later in the
- Select the root filesystem device for formatting (/dev/mapper/cryptdata type btrfs on top),
Use as'btrfs journaling filesystem', check
Format the partitionand use '/' as
- If you have other partitions, check their types and use; particularly, deactivate other EFI partitions.
Recheck everything, press the
Install Now button to write the changes to the disk and hit
Continue button. Select the time zone and fill out your user name and password.
If your installation is successful choose the
Continue Testing option.
DO NOT REBOOT!, but return to your terminal.
Return to the terminal and create a chroot (change-root) environment to work directly inside your newly installed operating system:
Now you are actually inside your system, so let's mount all other partitions and have a look at the btrfs subvolumes:
Looks great. Note that the subvolume
@ is mounted to
/, whereas the subvolume
We need to create the
Note that the UUID is from the luks partition
/dev/nvme0n1p3, not from the device
/dev/mapper/cryptdata! You can get all UUID using
There are many ways to encrypt the swap partition, a good reference is dm-crypt/Swap encryption. For the sake of this guide, I will only show how to set up it as an encrypted swap partition.
As I have no use for hibernation or suspend-to-disk, I will simply use a random password to decrypt
the swap partition using the
We also need to adapt the fstab accordingly:
The sed command simply replaced the UUID of your swap partition with the encrypted device
/dev/mapper/cryptswap. There you go, you have an encrypted swap partition.
The device holding the kernel (and the initramfs image) is unlocked by GRUB, but the root device
needs to be unlocked again at initramfs stage, regardless whether it’s the same device or not,
so you'll get a second prompt for your passphrase. This is because GRUB boots with the given
initramfs images; in other words, all devices are locked, and the root device
needs to be unlocked again. To avoid extra passphrase prompts at initramfs stage, a workaround
is to unlock via key files stored into the
initramfs image. This can also be used to unlock any
additional luks partitions you want on your disk. Since the
initramfs image now resides on an
encrypted device, this still provides protection for data at rest. After all for luks the volume
key can already be found by user space in the Device Mapper table, so one could argue that
including key files to the
initramfs image – created with restrictive permissions – doesn’t
change the threat model for luks devices. Note that this is exactly what e.g. the Manjaro
architect installer does as well.
Long story short, let's create a key-file, secure it, and add it to our luks volume:
Note that "Key Slot 0" contains our passphrase, whereas "Key Slot 1" contains the key-file. Let's restrict the pattern of keyfiles and avoid leaking key material for the initramfs hook:
These commands will harden the security options in the
intiramfs configuration file and hook.
Next, add the keyfile to your
Now it is time to finalize the setup and install the GRUB bootloader. First we need to make it
capable to unlock luks1-type partitions by setting
/etc/default/grub, then install the bootloader to the device
/dev/nvme0n1 and lastly update
GRUB. Just in case, I also reinstall the generic kernel
("linux-generic" and "linux-headers-generic") and also install the Hardware Enablement
kernel ("linux-generic-hwe-20.04" "linux-headers-generic-hwe-20.04"):
Lastly, double-check that the initramfs image has restrictive permissions and includes the keyfile:
Note that cryptsetup-initramfs may rename key files inside the initramfs.
Now, it is time to exit the chroot - cross your fingers - and reboot the system:
If all went well you should see a single passphrase prompt (YAY!) from GRUB:
where you enter the luks passphrase to unlock GRUB, which then either asks you again for your
passphrase or uses the key-file to unlock
/dev/nvme0n1p3 and map it to
If you added a key-file you need to type your password only once. Note that if you mistyped the
password for GRUB, you must restart the computer and retry.
Now let's click through the welcome screen and open up a terminal to see whether everything is set up correctly:
Look's good. Note that in this tutorial I installed both a swapfile and a swap partition. Normally you would choose one or the other.
Let's update the system and reboot one more time:
fstrim.timer as we did not add
discard to the
crypttab. This is due to the fact
that Btrfs Async Discard Support Looks To Be Ready For Linux 5.6
is quite new, but 20.04 still runs kernel 5.4, it is better to enable the
Open a terminal and install some dependencies:
Install Timeshift and configure it directly via the GUI:
- Select “BTRFS” as the “Snapshot Type”; continue with “Next”
- Choose your BTRFS system partition as “Snapshot Location”; continue with “Next”
- "Select Snapshot Levels" (type and number of snapshots that will be automatically created and
managed/deleted by Timeshift), my recommendations:
- Activate "Monthly" and set it to 1
- Activate "Weekly" and set it to 3
- Activate "Daily" and set it to 5
- Deactivate "Hourly"
- Activate "Boot" and set it to 3
- Activate "Stop cron emails for scheduled tasks"
- continue with "Next"
- I also include the
@homesubvolume (which is not selected by default). Note that when you restore a snapshot Timeshift you get the choice whether you want to restore it as well (which in most cases you don't want to).
- Click "Finish"
- "Create" a manual first snapshot & exit Timeshift
Timeshift will now check every hour if snapshots ("hourly", "daily", "weekly", "monthly", "boot") need to be created or deleted. Note that "boot" snapshots will not be created directly but about 10 minutes after a system startup.
Timeshift puts all snapshots into
/run/timeshift/backup. Conveniently, the real root
(subvolid 5) of your BTRFS partition is also mounted here, so it is easy to view, create,
delete and move around snapshots manually.
/run/timeshift/backup/@ contains your
/run/timeshift/backup/@swap contains your
Now let's install timeshift-autosnap-apt and grub-btrfs from GitHub
After this, optionally, make changes to the configuration files:
For example, as we don't have a dedicated /boot partition, we can set
timeshift-autosnap-apt-conf file to not rsync the
/boot directory to
Note that the EFI partition is still rsynced into your snapshot to
For grub-btrfs, I change
GRUB_BTRFS_SUBMENUNAME to "MY BTRFS SNAPSHOTS".
Check if everything is working:
Now, if you run
sudo apt install|remove|upgrade|dist-upgrade, timeshift-autosnap-apt will
create a snapshot of your system with Timeshift and grub-btrfs creates the corresponding boot
menu entries (actually it creates boot menu entries for all subvolumes of your system).
Hopefully this is of help to some of you who want to have a stable and reliable system! Let me know you thoughts in comments below.