Installing Arch Linux with an encrypted home

This post is a summary of how I installed my Arch Linux with an encrypted home.

Table of contents

Background

I recently received my new work computer, and the guys from the IT department asked me to perform encryption, at least of my home partition. This was the first time I tried to encrypt partitions during the Arch Linux install. I remember some of my friends trying to encrypt their home without encrypting their whole partition, and I remembered that they had had some problems, so I though I might as well encrypt the whole partition.

Another thing I remember from a long time ago is that it was considered a good practice to have your / and your /home on two separate partitions in case of crashes. I did that a couple of time, and when crashes occurred, I had never managed to fix them without wiping the whole disk, so eventually I stopped doing that.

This install caused me some problems, and this is why I write this post: if anyone else than myself reads it and finds help in it, I'm glad, but I mostly write it in case I need to do this once again.

So here I am, with my brand new machine, with an Ubuntu distribution that I obviously won't keep. I have my Arch Linux iso on my USB stick, and I'm ready to install.

The mistakes

When encrypting, if you have your / and /home on the same partition, and you want to encrypt your home, well, you'll be encrypting your /, and since /boot is in /, it will also be encrypted. Maybe your want to encrypt your /boot for security reasons, but it wasn't specially my case. The thing is encrypting your /boot leads to extra complexity, since you'll need to decrypt before booting.

This is why I decided to finally go back to putting / and /home on two separate partitions. That way, I encrypt my home, and that's all.

Another thing that a lot of people that encrypt disks use is LVM. Honestly, I don't know much about LVM, I just know that is adds a layer of complexity to the setup, and if I can avoid that, I might as well.

The subtleties

Docker

If you use docker, you know that it tends to need a lot of storage, and if you want to have a small / partition to have more space in your home, docker will be a problem very quickly.

The way I deal with this is to put the docker directory in /home/docker. That way, it will be encrypted (I don't know if it's very important, but if during dev, I write some private key in clear, I think it can still be useful), but most importantly, it's now in the partition where I have the most available space.

To do this, I just edit the /etc/docker/daemon.json file:

{
   "data-root": "/home/docker"
}

Wake-on-Lan

If you want to have Wake-on-Lan on your computer, and encrypt your disk, you may have the following problem: when you will try to wake your computer, and then it will prompt for your passphrase... but if you're remote, you're going to have some troubles to type it.

My solution for this is to configure your marchine so that no encryption setup is performed at boot: you skip a few steps (manual edition of /etc/mkinitcpio.conf and /etc/default/grub, it will be indicated in this tutorial), so that nothing special is performed at boot.

That way, when your computer boots, it won't ask for any passphrase, and simply won't mount your encrypted home.

Here where it gets tricky, on your / partition (with encrypted home not mounted), you will create a /home/$USER directory with a few files, so that your computer is usable without the home partition mounted. The only necessary file will be your /home/$USER/.ssh/authorized_keys, which will allow you to SSH your machine so that you can remotely mount your encrypted partition, but you can also have a nice .bashrc (or .zshrc) to help you mount your stuff.

I use my arch without login manager (lightdm or stuff like this), I just launch login in the TTY, and run startx to start my desktop manager, so my .zshrc on my / partition simply looks like this:

startx() {
    # I'm used to running startx right after I login, to this first mount my
    # disks and then runs startx.
    mount-disk

    # Don't start if disks aren't mounted.
    if [ $? -ne 0 ]; then
        return
    fi

    /bin/startx
}

mount-disk() {
    # In my home on my encrypted partition, I have an empty file in
    # $HOME/.mounted, this way, I can easily check if my encrypted partition is
    # mounted or not.
    if [ -f $HOME/.mounted ]; then
        echo "already mounted" >&2
        return
    fi

    # On my computer, I have two disks, one NVMe with my OS, and one HDD with
    # more space. I want three attempts at typing the passphrase.
    for retry in 1 2 3; do

        # Because they're encrypted with the same passphrase, I read the
        # passphrase once, and then decrypt both disks.
        sudo echo -n "Enter your passphrase: "
        read -s passphrase

        # Mount the NVMe encrypted partition
        echo "$passphrase" | sudo cryptsetup luksOpen /dev/nvme0n1p7 luks

        # If mounted correctly, break this loop and mount other partitions.
        if [ $? -eq 0  ]; then
            break
        elif [ $retry -eq 3 ]; then
            # If the third attempt failed, exit
            echo "Couldn't decrypt disk"
            return 1
        fi

    done

    sudo mount /dev/mapper/luks /home

    echo "$passphrase" | sudo cryptsetup luksOpen /dev/sda1 luks2

    sudo mount /dev/mapper/luks2 /mnt

    # Since my root partition is quite small, I can't put docker files on it,
    # so if docker is enabled in systemd, it will crash because the files are on
    # the partition that are not mounted yet, so I start it manually here.
    sudo systemctl start docker

    # Because we mounted the home partition on /home, our current working dir is
    # broken, so we re-cd to our home, and source our new zshrc.
    cd /home/$USER
    source .zshrc
}

The process

Booting the USB drive

As it always begin, I plug my USB drive into my computer, boot it and rapidly press F12, and make my computer boot on the USB drive. From there, I get a prompt, and as a french guy, with an azerty keyboard, I start by running

loadkeys fr

(which I need to type as loqdkeys fr since the default keyboard layout is the qwerty one).

Preparing the disk

Partitions

Then comes the part when we format the disk. As said previously, I'll have my / and /home on two separate partitions, and since I don't believe in swap, I made three partitions :

  • /dev/nvme0n1p1 that corresponds to /boot/efi, 100MB;
  • /dev/nvme0n1p2 that corresponds to /, 15GB (I want to keep it small because my laptop only has 512GB of SSD) 50GB, even if you have a small disk, be large on this one or you'll be in trouble later (happened to me numerous times, nowdays, I tend to set it as 10% of my disk size);
  • /dev/nvme0n1p3 that corresponds to /home, that fills the rest of my disk and that will be encrypted.

Then, we need to format those partitions. So it starts as usual:

mkfs.vfat -F32 /dev/nvme0n1p1
mkfs.ext4 /dev/nvme0n1p2
mkfs.ext4 /dev/nvme0n1p3 # This may be useless but I'm not sure

Encryption

Then we need to setup the encryption of our /dev/nvme0n1p3:

cryptsetup --type luks1 luksFormat /dev/nvme0n1p3

I'm not super sure the --type luks1 is required, but I use Grub as bootloader and I'm not sure it supports luks2.

Anyway, this will ask you for a passphrase. Finding a good passphrase is hard, but advice can be found online. I used diceware a source of inspiration.

When this is done, you need to mount your partitions to continue the install.

The following command remounts the encrypted disk to an unencrypted location:

cryptsetup luksOpen /dev/nvme0n1p3 luks

It creates a virtual disk in /dev/mapper/luks that you then need to format as well:

mkfs.ext4 /dev/mapper/luks
Note for non-qwerty keyboards

If you want your home partition to be decrypted on boot, and you have a beautiful passphrase but a non-qwerty keyboard, you may have a hard time typing in your passphrase when your computer will be booting, because changing your keyboard layout this early in the booting process is either very hard, or impossible.

The way I solve this issue (and I'm not the one who came up with this trick, I think I found it on stackoverflow but I can't find the original source), is to add a second decryption key, corresponding to what my passphrase would be if I typed it on the wrong keyboard layout.

I do this by:

  • running cryptsetup luksAddKey /dev/nvme0n1p3, with my french keyboard layout;
  • typing in my current passphrase, with my french keyboard layout;
  • switching to another TTY (Ctrl+Alt+F2), and logging in as root;
  • changing my keyboard layout to us (loadkeys us, not sure if it should be us or en)
  • switching back to my first TTY (Ctrl+Alt+F1);
  • typing in the same passphrase, and validating it.

If everything went well, you should now have two passphrases, corresponding to the same key strokes, but on different keyboard layouts, that way, if you're booting your computer, you'll use the qwerty keyboard layout, but if you're booting from a USB device to recover data after crashing your OS, you can still decrypt it with your regular keyboard layout.

Mount

If you don't care about Wake-on-Lan, you can start mounting everything everywhere:

mount /dev/nvme0n1p2 /mnt
mkdir -p /mnt/boot/efi && mount /dev/nvme0n1p1 /mnt/boot/efi
mkdir /mnt/home && mount /dev/mapper/luks /mnt/home

If you care about Wake-on-Lan, don't mount the home partition yet, so just mount the following:

mount /dev/nvme0n1p2 /mnt
mkdir -p /mnt/boot/efi && mount /dev/nvme0n1p1 /mnt/boot/efi

Install all the things

Now is the moment to pacstrap all the things. Make sure you have an internet connection, edit your /etc/pacman.d/mirrorlist to put the servers close to you at the top of the file, and here we go:

# Pacman may crash yelling that packages are invalid or correputed because of
# PGP keys, so you might need the two following lines in order for pacstrap to
# work
pacman-key --init
pacman-key --populate archlinux

# Install basic things
pacstrap /mnt base base-devel linux linux-firmware netctl dhclient dhcpcd wireless_tools wpa_supplicant dialog

Those should let you connect to the internet once the install is finished. Make sure to also install your favorite text editor.

You should also generate your fstab file:

genfstab -Up /mnt >> /mnt/etc/fstab

This file describes which partitions should be mounted and where when the computer boots. If you didn't mount your home yet, it will not appear in the fstab file, and so it won't be mounted during boot, which will allow you to mount it later (via SSH for example).

The chroot

Now comes the time to chroot.

arch-chroot /mnt

Welcome to your new computer. You can configure things such as the machine name, the timezone, the keyboard layout, etc... Don't hesitate to check the official guide for these parts, encryption doesn't change anything until the Initramfs (mkinitcpio).

You will certainly want to install more packages, pacman may give you a hard time again because of PGP keys, so you may need to run the following:

pacman-key --init
pacman-key --populate archlinux

Also, don't forget to set the root password with the passwd command.

Initramfs

To be honest, I have no idea what this does, but I know that it's very important. Start by running mkinitcpio -p linux. This should generate a file named /etc/mkinitcpio.conf.

If you want Wake-on-Lan, you can skip to the next section. If you want to decrypt your encrypted partition on boot, you will need to edit /etc/mkinitcpio.conf.

In this file you should add ext4 in the modules line, my line looks like this:

MODULES=(ext4)

and add encrypt just before filesystems in the hooks line, my line looks like this:

HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block encrypt filesystems fsck)

Then, run mkinitcpio -p linux once again, and you're done with that part.

Grub

Ok, there surely are alternatives to Grub, but Grub is the only thing I know so that's what I use. To install grub, you need to install two other packages:

pacman -S grub efibootmgr

Normally, you should still have your internet connection active from before the chroot.

If you don't care about Wek-on-Lan, and want your home partition decrypted and mounted, you will need to edit grub's default configuration . Edit the /etc/default/grub file. The line GRUB_ENABLE_CRYPTODISK=y should be uncommented, and I also changed the GRUB_CMDLINE_LINUX line:

GRUB_CMDLINE_LINUX="cryptdevice=/dev/nvme0n1p3:luks"

Once those modifications are done (or not), you need to install the grub:

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=arch_grub
grub-mkconfig -o /boot/grub/grub.cfg

and normally you should be all set.

Reboot

You can now exit the chroot (Ctrl+D or exit), umount the disks (umount -R /mnt) and reboot your computer.

When booting again, grub should start and run Arch Linux, and if configured like so, it will prompt you for you passphrase. When the passphrase is entered, it will prompt for your login and password and you can then continue your configuration.