Setting up LUKS encryption on an existing Ubuntu partition

PUBLISHED ON APR 13, 2025

This is a guide to enabling encryption on an existing unencrypted Ubuntu 24.04 partition. Assumptions:

  1. / and /boot are on different partitions. While it is possible to have a single partition with both the root / and /boot (GRUB), I wasn’t able to get this to work seamlessly, and so spent some time moving /boot to its own partition. We will also assume there’s an EFI partition mounted at /boot/efi. You can verify mount points by running mount with no arguments, or using gparted.
  2. The partition with / uses the ext4 system.
  3. Your swapfile is located in /, and so implicitly it will also be encrypted
  4. A backup of the entire disk is made. I used GNOME Disks to create an image. I ended up restoring from this backup thrice owing to various mistakes during the process!

⚠️ DISCLAIMER: This is a potentially destructive process. I am not responsible or liable for any data loss ⚠️

Install cryptsetup-initramfs

In your existing Ubuntu install, install the cryptsetup and cryptsetup-initramfs packages. The cryptsetup-initramfs package is needed to include the decryption module inside the initram image. If you forgot, and have already encrypted the partition, it is still possible to install these packages in a chroot environment via a startup disk.

sudo apt install cryptsetup cryptsetup-initramfs

Edit /etc/initramfs-tools/modules, and add these lines:

dm_crypt
aes_x86_64

At this point, you can optionally update the initramfs and ensure a bunch of crypto libraries are now included in the image:

sudo update-initramfs -u -k all
mkdir /tmp/contents
cd /tmp/contents
unmkinitramfs /boot/initrd.img-$(uname -r) .
find . -iname '*crypto*'

should print something like:

./main/usr/lib/x86_64-linux-gnu/libcrypto.so.3
./main/scripts/local-bottom/cryptopensc
./main/scripts/local-top/cryptopensc
./early3/usr/lib/modules/6.8.0-57-generic/kernel/drivers/net/ethernet/chelsio/inline_crypto
./early3/usr/lib/modules/6.8.0-57-generic/kernel/arch/x86/crypto
./early3/usr/lib/modules/6.8.0-57-generic/kernel/lib/crypto
./early3/usr/lib/modules/6.8.0-57-generic/kernel/crypto
./early3/usr/lib/modules/6.8.0-57-generic/kernel/crypto/crypto_user.ko.zst
./early3/usr/lib/modules/6.8.0-57-generic/kernel/crypto/crypto_engine.ko.zst
./early3/usr/lib/modules/6.8.0-57-generic/kernel/crypto/crypto_simd.ko.zst

Encrypt the partition

Boot into a live Ubuntu 24.04 startup-disk, and launch a terminal. Identify which Linux devices(dev/sdaXY or dev/nvmeXnYpZ) corresponding to the existing /, /boot and EFI partitions. You can do this either via running sudo blkid, or via gparted. We’ll refer to the Linux devices as follows:

ROOT_DEVICE=/dev/...
BOOT_DEVICE=/dev/...
EFI_DEVICE=/dev/...

The next few steps are taken verbatim from this super-useful guide, and perform the actual encryption:

# Run a filesystem check
sudo e2fsck -f "$ROOT_DEVICE"

# Make the filesystem slightly smaller to make space for the LUKS header
BLOCK_SIZE=`dumpe2fs -h $ROOT_DEVICE | grep "Block size" | cut -d ':' -f 2 | tr -d ' '`
BLOCK_COUNT=`dumpe2fs -h $ROOT_DEVICE | grep "Block count" | cut -d ':' -f 2 | tr -d ' '`
SPACE_TO_FREE=$((1024 * 1024 * 32)) # 16MB should be enough, but add a safety margin
NEW_BLOCK_COUNT=$(($BLOCK_COUNT - $SPACE_TO_FREE / $BLOCK_SIZE))
sudo resize2fs -p "$ROOT_DEVICE" "$NEW_BLOCK_COUNT"

# Run the encryption process. You will be prompted for a passphrase.
sudo cryptsetup reencrypt --encrypt --reduce-device-size 16M "$ROOT_DEVICE"

# Resize the filesystem to fill up the remaining space (i.e. remove the safety margin from earlier)
sudo cryptsetup open "$ROOT_DEVICE" recrypt
sudo resize2fs /dev/mapper/recrypt
sudo cryptsetup close recrypt

Note that cryptsetup rencrypt uses LUKS2 by default, which is known to have incompatibilities with GRUB. Again if boot/ is on a separate partition, this is not a concern. There is a command cryptsetup convert that can convert from LUKS2 to LUKS1, but it damaged my partition. It is likely reliable only for the more standard conversion path LUKS1 -> LUKS2.

Mount the partition

Let’s check if we can access the new partition. We will be mounting the decrypted filesystem at /dev/mapper/cryptroot.

sudo cryptsetup open $ROOT_DEVICE cryptroot
sudo mount /dev/mapper/cryptroot /mnt

At this point, if you browse /mnt you should see all the files from your partition.

Update crypttab and fstab

Figure out the UUID of the LUKS-encrypted partition, and that of the filesystem inside.

ls -l /dev/disk/by-uuid

Your output would look like:

# ...
lrwxrwxrwx 1 root root 10 Apr 13  2025 118d66fd-a11c-43c7-ab8a-ad098c7d41cb -> ../../dm-0 # <--- filesystem UUID
lrwxrwxrwx 1 root root 15 Apr 13  2025 ff8969f0-609f-487e-aef7-dd455a695e51 -> ../../nvme0n1p5 # <--- LUKS partition UUID
# ...

You’ll need these two UUIDs going forward. The one corresponding to dm-* is the actual filesystem inside the LUKS partition, and the one corresponding to $ROOT_DEVICE is the LUKS partition UUID.

The physical hard drive is divided into logical partitions. We have setup LUKS encryption on one of these partitions. Inside the LUKS encrypted partition (container), there is a filesystem corresponding to /. These two layers each have their own UUID - one for the encrypted container itself, and one for the filesystem inside it. Depending on what configuration file we’re updating, we’ll need to use the appropriate UUID.

crypttab

Edit /mnt/etc/crypttab (NOT /etc/crypttab) and add an entry with the LUKS partition UUID:

cryptroot UUID=<LUKS partition UUID> none luks,discard # discard is SSD-specific

fstab

Edit /mnt/etc/fstab (NOT /etc/fstab) and modify the existing entry for / if needed, like:

UUID=<filesystem UUID> /               ext4    errors=remount-ro 0       1

GRUB

Edit /mnt/etc/default/grub (NOT /etc/default/grub) and update or add GRUB_CMDLINE_LINUX like so:

GRUB_CMDLINE_LINUX="cryptdevice=UUID=<LUKS partition UUID>:cryptroot root=/dev/mapper/cryptroot"

Note you do not need to set GRUB_ENABLE_CRYPTODISK. That is needed if /boot was also encrypted.

Setup chroot environment

Run:

sudo -s # Enter a super-user shell
mount --bind /dev /mnt/dev
mount --bind /dev/pts /mnt/dev/pts
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
mount --bind /run /mnt/run
mount $BOOT_DEVICE /mnt/boot
mount $EFI_DEVICE /mnt/boot/efi
chroot /mnt

Note that if you hadn’t installed cryptsetup-initramfs earlier, now is another opportunity to!

Update initramfs

Update initramfs and GRUB like so:

update-initramfs -u -k all
update-grub

Reboot, and check you are able to boot into your OS. If all goes well, you will be prompted by the regular GRUB screen, and during the boot process will be prompted for the passphrase. If you run sudo cryptsetup status cryptroot, you should see something like:

/dev/mapper/cryptroot is active and is in use.
  type:    LUKS2
  cipher:  aes-xts-plain64
  keysize: 512 bits
  key location: keyring
  device:  /dev/nvme0n1p5
  sector size:  512
  offset:  16384 sectors
  size:    487634944 sectors
  mode:    read/write
  flags:   discards 

Troubleshooting

When booting, you get thrown into a BusyBox shell because no root partition was found

Its likely you missed the cryptsetup-initramfs step. In the BusyBox shell, check if you can run cryptsetup. If you can’t, boot into the startup disk and follow the instructions to create a chroot environment. Then follow the steps to install cryptsetup-initramfs.

Bonus

If you’re the only user on your machine, you can enable “Automatic login” via Settings > Users to avoid needing to type your user password in addition to the LUKS passphrase.

Click the Unlock.. button to change the setting

Click the Unlock.. button to change the setting