ArchLinux install with encrypted BTRFS
In this article I will show you how to install ArchLinux on a BTRFS drive with an encrypted fs. I used this setup multiple times and I consider it solid. Since with the official documentation is not easy to arrive at these conclusion, and with the input from a friend that asked for it, here I write down what I know.
Prerequisites
Download and copy on an USB drive the latest install ISO of ArchLinux.
If you are installing it in dual boot with Windows, it’s recommended that you resize its partition from within Windows itself, to avoid data corruption. To do so search for “Create and format partitions” on the Windows search bar, open “Disk Management”, select the Windows C partition and resize it to the desired size, to create a free space to install Linux.
Boot the computer from the USB drive, ensuring to select EFI boot mode (the GRUB menu should be visible). You should be at a shell prompt logged in as root. The network should be already configured if an ethernet cable is attached. Try to ping an host to confirm that internet is reachable (it will be needed later).
Setup partitions
Now we need to create the required partitions. For this setup we will create three partitions:
# | filesystem | size | description |
---|---|---|---|
1 | FAT32 | 500M | EFI partition |
2 | luks | 100% | root partition |
NOTE: when dual booting with Windows you only need to create the / partition, not a new label or the EFI partition!
To do so, we can use the fdisk
command (but feel free to use any other program, such as cgdisk
or gparted
).
root@archiso ~ # fdisk /dev/sda
Welcome to fdisk (util-linux 2.39.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): g
Created a new GPT disklabel (GUID: C2D253F4-B9C7-4F11-8DF8-18BE2D671531).
Command (m for help): n
Partition number (1-128, default 1):
First sector (2048-67108830, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-67108830, default 67106815): +500M
Created a new partition 1 of type 'Linux filesystem' and of size 500 MiB.
Command (m for help): t
Selected partition 1
Partition type or alias (type L to list all): 1
Changed type of partition 'Linux filesystem' to 'EFI System'.
Command (m for help): n
Partition number (2-128, default 2):
First sector (1026048-67108830, default 1026048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (1026048-67108830, default 67106815):
Created a new partition 2 of type 'Linux filesystem' and of size 31.5 GiB.
Command (m for help): p
Disk /dev/sda: 32 GiB, 34359738368 bytes, 67108864 sectors
Disk model: QEMU HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: C2D253F4-B9C7-4F11-8DF8-18BE2D671531
Device Start End Sectors Size Type
/dev/sda1 2048 1026047 1024000 500M EFI System
/dev/sda2 1026048 67106815 66080768 31.5G Linux filesystem
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Now we need to format the EFI partition (skip this step in case of a dual boot):
root@archiso ~ # mkfs.vfat /dev/sda1
Finally, we need to create the LUKS volume:
root@archiso ~ # cryptsetup luksFormat /dev/sda2
WARNING!
========
This will overwrite data on /dev/sda2 irrevocably.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sda2:
Verify passphrase:
cryptsetup luksFormat /dev/sda2 30.31s user 3.80s system 137% cpu 24.815 total
WARNING: write down your passphrase somewhere safe! If you loose it, all your data will be irrecoverable.
Now that we created the LUKS volume, we need to open up. When opening an encrypted volume a new block device will be created using the Linux device mapper functionality. We then can treat this device as any other physical partition, and thus create on it a filesystem. Encryption is done transparently by the kernel at a block level.
root@archiso ~ # cryptsetup luksOpen /dev/sda2 root
Enter passphrase for /dev/sda2:
cryptsetup luksOpen /dev/sda2 root 8.13s user 2.21s system 155% cpu 6.662 total
NOTE: root is just a name that we can choose to identify the device. We can give it whatever name we want!
Finally, we create our BTRFS filesystem, as we would do on a normal partition:
root@archiso ~ # mkfs.btrfs /dev/mapper/root
btrfs-progs v6.3.3
[...]
Devices:
ID SIZE PATH
1 31.49GiB /dev/mapper/root
Now, we mount it and create subvols:
root@archiso ~ # mount /dev/mapper/root /mnt
root@archiso ~ # btrfs subvolume create /mnt/@
Create subvolume '/mnt/@'
root@archiso ~ # btrfs subvolume create /mnt/@home
Create subvolume '/mnt/@home'
root@archiso ~ # btrfs subvolume list /mnt
ID 256 gen 7 top level 5 path @
ID 257 gen 8 top level 5 path @home
root@archiso ~ # btrfs subvolume set-default 256 /mnt
root@archiso ~ # umount /mnt
NOTE: the set-default
command sets the default subvolume. This is the subvol that is mounted if a different subvol is not specified. This is important, as we will see later, and will avoid us setting another kernel parameter just to tell on which subvol / resides!
We then mount all the filesystems:
root@archiso ~ # mount /dev/mapper/root /mnt
root@archiso ~ # ls /mnt # NOTE: it's empty! This is because we are indeed in the @ subvol
root@archiso ~ # mkdir /mnt/{home,boot}
root@archiso ~ # mount /dev/mapper/root -o subvol=@home /mnt/home
root@archiso ~ # mount /dev/sda1 /mnt/boot
root@archiso ~ # mount
[...]
/dev/mapper/root on /mnt type btrfs (rw,relatime,space_cache=v2,subvolid=256,subvol=/@)
/dev/mapper/root on /mnt/home type btrfs (rw,relatime,space_cache=v2,subvolid=257,subvol=/@home)
/dev/sda1 on /mnt/boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro)
We are now ready to install, as usual:
root@archiso ~ # pacstrap /mnt base base-devel linux vim
[...]
root@archiso ~ # genfstab -p /mnt >> /mnt/etc/fstab
root@archiso ~ # arch-chroot /mnt
[root@archiso /]#
We are now into the new installed system. Now we need to to a couple of configurations, start with the usual ones:
[root@archiso /]# passwd # I always forget this step... so better do it first!
New password:
Retype new password:
passwd: password updated successfully
[root@archiso /]# vim /etc/locale.gen # uncomment the locales you want to generate
[root@archiso /]# locale-gen
Generating locales...
en_US.UTF-8...
[root@archiso /]# echo LANG=en_US.UTF-8 >> /etc/locale.conf # or whatever locale you choose
[root@archiso /]# ln -s /usr/share/zoneinfo/Europe/Rome /etc/localtime # change with your timezone
[root@archiso /]# echo archbook > /etc/hostname # choose your hostname
[root@archiso /]# vim /etc/hosts # and don't forget the hosts file
# add a line like so:
# 127.0.0.1 localhost
# 127.0.0.1 archbook archbook.domain
It’s now a good time to install all the other software that may be required after the reboot (such as software to get the computer online, especially if using Wi-Fi). I will not install nothing since I prefer to it so later on.
Now, we need to make some changes to the initrd to include the required modules:
[root@archiso /]# vim /etc/mkinitcpio.conf
# add `encrypt` to the HOOKS line before `filesystems`, as here:
# HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block encrypt filesystems fsck)
[root@archiso /]# mkinitcpio -p linux # rebuild initrd
Finally, install the bootloader. For simplicity I like systemd-boot
:
[root@archiso /]# bootctl install
Created "/boot/EFI".
Created "/boot/EFI/systemd".
Created "/boot/EFI/BOOT".
Created "/boot/loader".
Created "/boot/loader/entries".
Created "/boot/EFI/Linux".
Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/systemd/systemd-bootx64.efi".
Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/BOOT/BOOTX64.EFI".
⚠️ Mount point '/boot' which backs the random seed file is world accessible, which is a security hole! ⚠️
⚠️ Random seed file '/boot/loader/.#bootctlrandom-seedbec08f14bf68c581' is world accessible, which is a security hole! ⚠️
Random seed file /boot/loader/random-seed successfully written (32 bytes).
Successfully initialized system token in EFI variable with 32 bytes.
Created EFI boot entry "Linux Boot Manager".
We finally have only to write the configuration file for the bootloader.
Create the entry file /boot/loader/entries/arch.conf
with this content:
title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options root=/dev/mapper/root rw cryptdevice=/dev/disk/by-uuid/4e3342c8-03a8-43e3-87c1-283e5812dde4:root:allow-discards
NOTE: It’s recommended to use UUIDs for the disk, since the names such as sda1
may change when you add/remove disks from your system. To know the UUID of your partition, use the command blkid /dev/sdYX
.
Finally, edit the loader file /boot/loader/loader.conf
specifying the default entry:
timeout 3
console-mode keep
default arch.conf
NOTE: for additional security you may want to disable the editing of the kernel command line, that can be used to get a root shell (tough the root disk is still encrypted an attacker may install malware in the /boot partition!). To do so add the option editor no
to the loader.conf
file.
Now, we just have to reboot the machine and hope everything is fine!
[root@archiso /]# exit
exit
arch-chroot /mnt 45.02s user 40.38s system 6% cpu 21:18.02 total
130 root@archiso ~ # reboot
Congratulations! The system should now boot, ask you for a passphrase, and then bring you to the login prompt. From now on you can follow the standard ArchLinux post installation guide.
If you want to improve or comment this guide, please do so on GitHub!