1. Home
  2. Docs
  3. Encrypted Installation
  4. BTRFSonLUKS – verbose version

BTRFSonLUKS – verbose version

by 2000

Full disk encryption: BTRFSonLUKS with separate root, home and pkg subvolumes; hibernation with a swapfile; auto-snapshots with easy system rollback (GUI); boot into snapshots

Note: If you’re installing to a dedicated hdd/sdd just copy & paste the commands provided in the wiki article BTRFSonLUKS – quick copy&paste version. The result should be identical but with far less reading ;-).

The following information is just for the technical interested and/or in the event you have a more complicated setting (e. g. dual boot and/or already have multiple vfat or luks partitions); in which case the provided commands in the copy&paste version may mess up your existing setup and need to be adjusted according to the info below.

What you’ll end up getting:

  • BTRFSonLUKS (fully LUKS encrypted single partition containing a btrfs filesystem with /boot, /‘root’ and /home)
  • /, /home, swapfile, pkg cache as separate subvolumes to allow easy and storage space saving snapshotting of root system
  • automated creation of snapshots (on system upgrade & daily & boot)
  • ability to boot into a working snapshot from the grub menu (automated creation of boot entries) and then setting this or other snapshot as new default system (from GUI)
  • swapfile, with the ability to hibernate

Not everybody always has the time, knowledge and/or will to go through the process of chrooting, downgrading, and repairing if something breaks.
With this low-maintenance type of setup it should be possible to recover/rollback from a problematic upgrade by simply booting into a working snapshot (these snapshots are created automatically) and setting this as the new default from within the booted system. You could then just wait a couple of days and then check if the upgrade problems still persist. Most of the time the problem will be fixed upstream by then. Note that the creation or restore of a snapshot takes about a second!

The following is a tutorial on setting up this type of system with the help of calamares (the EOS installer) and the cli.

++++++++++++++++++++++++++++++++++++++++++

#01 – Boot into Live-CD environment & set up partitions

With the help of GParted, just follow the steps described below or adjust to your needs.


(a) for UEFI systems:

  • create a GPT partition table
  • create sda1 with 300 to 512MiB, format as fat32 and set boot & esp flag
  • leave rest unallocated

+------------------+---------------------------+
| 300-512MiB       |      rest            xGiB |
| flag: boot & esp |      unallocated          |
| format: fat32    |                           |
| /dev/sda1        |                           |
+------------------+---------------------------+

(b) for BIOS (legacy boot) systems:

  • create a GPT partition table
  • create sda1 with 8MiB, leave unformatted and set bios_grub flag
  • leave rest unallocated

+------------------+---------------------------+
| 8MiB             |      rest            xGiB |
| flag: bios_grub  |      unallocated          |
| unformatted      |                           |
| /dev/sda1        |                           |
+------------------+---------------------------+

With other storage types, /dev/sda1 could also be called /dev/nvme0n1p1 for example; in this case just substitute sda1 with nvme0n1p1.


#02OPTIONAL – Change default btrfs calamares settings for fstab

By default the Calamares installer only uses btrfs compression (lzo method) if it detects a ssd.
One can change the used compression method(s) in the installed system itself later on, but this would only compress new files and require recompression of all old files. So why not skip these extra steps and let the installer get it right in one go without adding any extra time to the install.

The following will force calamares to assign and use compression on all btrfs installation devices; regardless of being ssd or hdd. We’ll use zstd compression.

You can find some information about btrfs compression here.

Edit /usr/share/calamares/modules/fstab.conf by running

sudo leafpad /usr/share/calamares/modules/fstab.conf

and change compress=lzo to compress=zstd in the ssdExtraMountOptions: [...] btrfs: section.

If you want to use compression on a hdd also, just add compress=zstd after autodefrag in the mountOptions: [...] btrfs: section. Save & exit.


#03 – Install system with calamares (off- or online install)

Set up calamares like you usually would (Location, Keyboard, Users, …) but
choose Manual partioning and edit (double-click the partition(s) in the list view) to the specifications given below …


(a) for UEFI systems:

  1. /dev/sda1
  • Mount point -> /boot/efi
  • set boot flag
  • keep fat32

  1. free space
  • Mount point -> /
  • File system -> btrfs
  • Encrypt: choose a secure password

Let Calamares finish the installation. If you get a warning about missing esp or boot flag(s) on /dev/sda1 just add them with GParted and continue with the install.


(b) for BIOS (legacy boot) systems:

  1. free space
  • Mount point -> /
  • File system -> btrfs
  • Encrypt: choose a secure password

Let Calamares finish the installation. Ignore the window notice “Option to use GPT on BIOS”. We had that set up by gparted already. Continue with the install.


After the install finishes, do NOT check the “Restart now” checkbox.


#04 – Mount newly installed btrfs system to temporary directory /mnt/btrfs
sudo mkdir /mnt/btrfs

Find your still unlocked luks device which contains the newly installed system.

sudo blkid -o device | grep luks

The command should produce something like /dev/mapper/luks-4e2dc3d4-16ce-44b9-a6be-a4a73a06e854. Your luks-… device UUID will differ though.

If the command returns more than one /dev/mapper/luks-… line you may have to run lsblk and/or sudo blkid and identify the right one.

Now mount the decrypted device to /mnt/btrfs. Be sure to use the right luks-… device!

sudo mount -o subvolid=5 /dev/mapper/luks-4e2dc3d4-16ce-44b9-a6be-a4a73a06e854 /mnt/btrfs

#05 – Adjust/repair fstab for brtfs

If the root file system is btrfs, the fsck order should be set to 0 instead of 1 or higher. The standard fsck has no effect on btrfs partitions and therefore can/should be disabled. Calamares doesn’t set this up right for btrfs partitions and subvolumes so we’ll correct this.

Edit /mnt/btrfs/@/etc/fstab by running

sudo leafpad /mnt/btrfs/@/etc/fstab

Change the last number of all lines that start with your /dev/mapper/luks-… device (the one from above) to 0. Save & exit.


#06 – Create a top-level subvolume for the pacman cache

Calamares has automatically set up / (root) and /home as separate top-level subvolumes. This has the advantage that although /home being mounted under /, if we snapshot the root subvolume /, the /home data and all other subvolumes won’t be stored in that snapshot. We can later restore any root snapshot without affecting the /home or other subvolume data.

On Arch Linux, a subvolume for /var/cache/pacman/pkg is often recommended to make sure the large pacman cache, that often contains GB’s of changing but easily redownloadable data, is excluded from snapshots. (Other canditates for exclusion, e. g. /var/abs, /var/tmp, /srv, aren’t part of this tutorial.)
I ran into some trouble during testing when restoring snapshots while setting this up as nested subvolumes, so I decided to stick to top-level subvolumes for this. The downside is we’ll need an entry in fstab for each top-level subvolume.

Create a top-level subvolume named @var-cache-pacman-pkg that will hold all future data stored in /var/cache/pacman/pkg.

sudo btrfs subvolume create /mnt/btrfs/@var-cache-pacman-pkg

As we have a newly installed system, /var/cache/pacman/pkg is still empty, so we don’t need to move any existing data.
We just need to add an entry to /etc/fstab to mount our newly created subvolume to /var/cache/pacman/pkg on the next system start.

  • 1. Edit /mnt/btrfs/@/etc/fstab with
sudo leafpad /mnt/btrfs/@/etc/fstab
  • 2. Duplicate the line starting with /dev/mapper/luks-... that contains /home

In this newly created duplicate entry

  • 3. replace /home with /var/cache/pacman/pkg
  • 4. replace @home with @var-cache-pacman-pkg

Save & exit.

ALTERNATIVELY, you can substitute steps 1. – 4. by running the following commands

fstabstr=`grep "/home" /mnt/btrfs/@/etc/fstab`
fstabstr=${fstabstr//\/home/\/var\/cache\/pacman\/pkg}
fstabstr=${fstabstr//@home/@var-cache-pacman-pkg}
sudo sh -c "echo $fstabstr >> /mnt/btrfs/@/etc/fstab"

#07Optional – Make a swap file in it’s own top-level subvolume & activate hibernation

Note: If you want to use hibernation, then you must add swap because the content of the RAM will be written to the swap partition/file. This also means that the swap size should be at least the size of RAM. Read here about choosing swap sizes for example.

Swap files in btrfs are supported since Linux kernel 5.x but the swap file cannot be on a snapshotted subvolume. The proper procedure is to create a new subvolume to place the swap file in.


#- Create subvolume named @swap (which will be mounted as /swap in the future)

sudo btrfs subvolume create /mnt/btrfs/@swap

#- Create mountpoint /swap

sudo mkdir /mnt/btrfs/@/swap

#- Create an entry in /etc/fstab to mount the subvolume @swap to /swap on every boot

sudo leafpad /mnt/btrfs/@/etc/fstab

Add the following line …

/dev/mapper/luks-4e2dc3d4-16ce-44b9-a6be-a4a73a06e854 /swap btrfs subvol=@swap,defaults,compress=no 0 0

Make sure to use your luks-UUID! The compress=no makes sure that that there won’t be any btrfs-compression applied to this subvolume holding our swap file. Swap files and btrfs compression don’t do well together!

Save and exit.


#- Create the actual swap file

The following will create and activate a swap file of e. g. 8GB size named swapfile in the subvolume @swap. Read here about general swap file creation. Don’t forget to adjust the size to your needs.

sudo truncate -s 0 /mnt/btrfs/@swap/swapfile
sudo chattr +C /mnt/btrfs/@swap/swapfile
sudo btrfs property set /mnt/btrfs/@swap/swapfile compression none

sudo fallocate -l 8G /mnt/btrfs/@swap/swapfile

sudo chmod 600 /mnt/btrfs/@swap/swapfile
sudo mkswap /mnt/btrfs/@swap/swapfile
sudo swapon /mnt/btrfs/@swap/swapfile

#- Edit /etc/fstab to enable the swap file after reboot

sudo leafpad /mnt/btrfs/@/etc/fstab

Add the following line …

/swap/swapfile none swap defaults 0 0

Save and exit.


#- Optional: Set up Hibernation into swap file on Btrfs

We need to let the system know the physical offset of our newly created swap file. This wiki entry describes how to do this for btrfs.

  1. Download and compile a tool to calculate the physical offset of the swap file …
wget https://raw.githubusercontent.com/osandov/osandov-linux/master/scripts/btrfs_map_physical.c
gcc -O2 -o btrfs_map_physical btrfs_map_physical.c
  1. Now run the tool …
sudo ./btrfs_map_physical /mnt/btrfs/@swap/swapfile
  1. Note the the first physical offset returned by this tool (the last number of the first line containing numbers). In this example, we use 5749440512.
  2. Also note the pagesize (usually 4096) that can be found with
getconf PAGESIZE
  1. To compute the resume_offset value, divide the physical offset by the pagesize. In this example, it is 5749440512 / 4096 = 1403672 .
  2. We need to add the resume_offset to /etc/default/grub
sudo leafpad /mnt/btrfs/@/etc/default/grub

Add resume_offset=1403672 (be sure to use your calculated offset!) after loglevel=3 on the line starting with GRUB_CMDLINE_LINUX_DEFAULT= .

  1. We also need to add the resume device to /etc/default/grub
    Copy the entry starting with root=/dev/mapper/luks-... and paste before loglevel=3 on the line starting with GRUB_CMDLINE_LINUX_DEFAULT= but substitute root= with resume=.

Save & exit.

  1. Configure the initramfs
    When an initramfs with the base hook is used, which is the default, the resume hook is required in /etc/mkinitcpio.conf . Whether by label or by UUID, the swap partition is referred to with a udev device node, so the resume hook must go after the udev hook.
sudo leafpad /mnt/btrfs/@/etc/mkinitcpio.conf

Add resume after filesystems on the line starting with HOOKS= . Save & exit.

You will need to let the system know that your grub and initramfs settings have changed. This is covered in the next section.


#08 – Let the system know that some things have changed & install some needed software

#- chroot into your system

  1. make a temporary folder and mount your root system and efi folder
sudo mkdir /mnt/chroot

Mount the root system to the newly created folder. Use your luks-… device (see #04).

sudo mount -o compress=zstd,subvol=@ /dev/mapper/luks-4e2dc3d4-16ce-44b9-a6be-a4a73a06e854 /mnt/chroot

Only on UEFI systems: Mount the partition containing your EFI data (e. g. /dev/sda1) to /mnt/chroot/boot/efi

sudo mount /dev/sda1 /mnt/chroot/boot/efi
  1. now chroot into the mounted system
sudo arch-chroot /mnt/chroot

#- While we’re in the chroot environment we’ll just install some software we’ll need later on to our newly installed system.

sudo pacman --noconfirm -S cronie
sudo systemctl enable cronie.service

#- Now we’ll update Grub and generate updated kernel images.

sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo mkinitcpio -p linux

#09REBOOT into your new system & run …
sudo pacman --noconfirm -Syy &&
yay --noconfirm -S timeshift timeshift-autosnap grub-btrfs

This will install the following:

  • timeshift => A system restore utility for Linux
  • timeshift-autosnap => Timeshift auto-snapshot script which runs before package upgrades using Pacman hook.
  • grub-btrfs => Includes btrfs snapshots in GRUB boot options

#10 – Configure Timeshift (/etc/timeshift.json)
  1. Open Timeshift from the menu
  2. Select “BTRFS” as the “Snapshot Type”; continue with “Next”
  3. Choose your btrfs system partition as “Snapshot Location”; continue with “Next”
  4. “Select Snapshot Levels” (type and number of snaphots that will be automatically created and managed/deleted by Timeshift)
    Recommendation:
  • Keep “Daily” at 5
  • Activate “Boot”, but change to 3; continue with “Finish”
  1. Optional: “Create” a manual first snapshot & exit Timeshift

Timeshift will now check on every full hour if snapshots (hourly, daily, weekly, monthly) need to be created or deleted. Note that boot snapshots will actually be created about 10 minutes after boot, not directly at system startup!


#11 – Configure timeshift-autosnap (/etc/timeshift-autosnap.conf)

Timeshift-autosnap creates timeshift snapshots whenever it detects a pacman (and yay invoked) upgrade. This way you should be able to rollback to a state right before the package upgrades.

sudo leafpad /etc/timeshift-autosnap.conf

By default only the last 3 snapshots are kept. You may want to increase the number somewhat (e. g. maxSnapshots=6) because if you invoke a system update by yay for example, there will often be two snapshots created. If you keep a maximum of 6 snapshots you’ll make sure to have at least 3 upgrade cycles worth of snapshots to revert to.


#12 – Configure grub-btrfs (/etc/default/grub-btrfs/config)

Grub-btrfs creates Grub boot entries for your snapshots. I recommend leaving the configuration as is.

Grub-btrfs should also be able to monitor the snapshot folder for changes and automatically update grub if it detects such a change. I wasn’t able to get this functionality to work reliably and therefore decided to just update the grub boot entries on every system shutdown (see #13).


#13 – Limit the maximum amount of snapshots & update grub boot entries

Timeshift cleans the automatically created snapshots and timeshift-autosnap has a default limit of 3 snapshots after upgrades, BUT the ones you create manually aren’t handled by Timeshift and would be kept indefinetily. High amounts of old snapshots could potentially cause slowdowns, so we’re going to limit the amount of maximum snapshots your system will allow and keep.

For this we will create a systemd service that runs right before you shutdown or restart the system and

  • keeps only the newest (e. g. 15) snapshots and deletes all the older ones
  • updates grub to contain only these snapshots as boot entries

I recommend to limit the amount of snapshots to about 13 to 15.

Create a systemd service called “limit-timeshift-snapshots-update-grub”:

sudo leafpad /etc/systemd/system/limit-timeshift-snapshots-update-grub.service

Now add the following content (you can adjust the number of snapshots to keep by changing the number from 15 to whatever in the ExecStop=... line; just choose a high number if you prefer to delete these manually):

[Unit]
Description=Keep only latest 15 timeshift snapshots and update grub.cfg before shutdown
Before=poweroff.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/true
ExecStop=/usr/bin/sh -c "cd /run/timeshift/backup/timeshift-btrfs/snapshots/ && rm -rf `ls -1r | awk 'NR>15'` && /usr/bin/grub-mkconfig -o /boot/grub/grub.cfg"


[Install]
WantedBy=multi-user.target

Save & exit.

Next we’ll enable and start the newly created service.

sudo systemctl enable limit-timeshift-snapshots-update-grub.service &&
sudo systemctl start limit-timeshift-snapshots-update-grub.service

DONE! You should now have a fully encrypted system with the ability to rollback to automatically (and manually) created snapshots and be able to hibernate.

Note that this setup isn’t meant to be a backup strategy replacement! The snapshots are stored on the same disk as your system; if this fails the snapshots won’t be accessible. At least your /home subvolume should be backuped to another physical device. So, just apply your normal backup strategy of choice.

++++++++++++++++++++++++++++++++++++++++++

#How to RESTORE a snapshot

A – If you ever need to reset your system to a stored state, just

  1. Launch Timeshift from the menu (or desktop shortcut)
  2. Select a snapshot and hit restore
  3. Reboot

That’s all. Takes mere seconds and doesn’t get any easier.
BTW, you could also restore a snapshot from the cli!


B – In case you can’t boot into your desktop environment try to

  1. Boot directly into a snapshot from the GRUB (boot) menu
  2. see A (above) …

C – In case you need to restore a snapshot from a live system (e. g. EndeavourOS Install medium)

  1. Boot into the live environment
  2. Install Timeshift into the live environment by executing
sudo pacman --noconfirm -Syy cronie
yay --noconfirm -S timeshift
 
  1. see A (above) …

D – In case you need to chroot from a live system (e. g. EndeavourOS Install medium)

  1. Boot into the live environment
  2. Decrypt and mount your luks partition (e. g. /dev/sda2)
sudo cryptsetup luksOpen /dev/sda2 crypt &&
sudo mount -o compress=zstd,subvol=@ /dev/mapper/crypt /mnt
 
  1. Only on UEFI systems: Mount your EFI boot folder (e. g. /dev/sda1)
sudo mount /dev/sda1 /mnt/boot/efi
  1. chroot into your system
sudo arch-chroot /mnt
  1. Do some root stuff …

++++++++++++++++++++++++++++++++++++++++++

Initially posted on the forum: 2020-03-03
Wiki version: 2020-07-27


Follow us
Was this article helpful to you? Yes 1 No

How can we help?