LUKS2/PBKDF2 encrypted /boot & GRUB

Okay, seems to have worked, but it was nowhere near as long.

No error message.

1 theme, 4 images found

Boot menu entry for UEFI Firmware Setting added

19 snapshots found

/tmp/grub-btrfs unmounted

Should be fine, who knows what these commands do without parameters, could read your whole drive looking for… whatever.

Anyway, then you’re close to reboot and see if all this effort works out. Fingers crossed!

Now, this is not in the instructions, but be careful with Secureboot and Windows Bitlocker: I know from experience that when Bitlocker detects changes in hardware/system setup, it may require your backup key to allow unlocking and booting Windows. That’s why - when I was still using Windows - I always made sure I had this backup key, and eventually got rid of Secureboot because it annoyed the heck out of me.

Edit: just cat /boot/grub/grub.cfg and verify if you see the cryptodisk reference.

Got it somewhere :rofl:

I definitely recommend using a UEFI start-up password.

That way, you can relax and remove the stick after the beep.

UPDATE:

Passwort wurde geschluckt, bin im GRUB :partying_face:

Password has been accepted, GRUB is running.

It says:

You need to load the kernel first

Where are you seeing this error? At boot after Step 10, or while still in the chroot running Step 9? And did the grep -i cryptodisk /boot/grub/grub.cfg return anything?

Reboot after step 10 from internal SSD.

Yes, it said done and returned what I summarised above.

But the first time the output was much bigger and I asked myself whether it could have been copypasted from # to #.

Ok, I personally have no clue what is going on, and have to rely on AI here:

Likely cause: grub-mkconfig generated wrong paths for the kernel inside the Btrfs subvolume. Since the root filesystem uses subvolumes (@ mounted as /), GRUB needs to know about the @ subvolume prefix to find /boot/vmlinuz-*.

You need to boot the live USB again, chroot back in (Step 5; make sure it is fully chrooted), and:

  1. Check what grub-mkconfig generated:

grep -i vmlinuz /boot/grub/grub.cfg

  1. Check where the kernel actually is:

ls /boot/vmlinuz-*

  1. Check if GRUB_CMDLINE_LINUX_DEFAULT and the cryptodisk setup are correct:

grep -i cryptodisk /boot/grub/grub.cfg

The kernel path in grub.cfg should reference the correct Btrfs subvolume. If the paths are wrong, you may need to set GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION=true in /etc/default/grub and regenerate (as a workaround, better just try and fix the paths so they point to the correct location).

Edit: the good news is that grub does decrypt the device, just can’t find the kernel (details!).

  1. Kernel, root=UUID(Container), rw, rootflags=subvol=@, nowatchdog nvme_load=YES zswap.enabled=0, rd.luks.name=UUID(Partition6)=cryptroot, splash loglevel=3

(the same once more)

(the same a third time, just with the lts kernel)

  1. /boot/vmlinuz-cachyos

  2. 5 lines of insmod cryptodisk

It can’t have been grub-mkconfig without -o …

I’m reading that right now.

Re-entering it also returns the previously long output.

I’ll take a break here until the next time it suits me.

Running grub-mkconfig without parameters doesn’t change anything, it seems very unlikely that is the cause. The most likely cause is a btrfs subvolume path issue: GRUB sees the raw btrfs top-level, so it needs /@/boot/vmlinuz-cachyos, not /boot/vmlinuz-cachyos.

Show the exact linux lines (with the file path, not just parameters)
grep ‘linux /’ /boot/grub/grub.cfg

Check what grub-mkrelpath thinks the path should be
grub-mkrelpath /boot/vmlinuz-cachyos

Confirm btrfs module is loaded too
grep ‘insmod btrfs’ /boot/grub/grub.cfg

The first two are the most important. If the linux lines show /boot/vmlinuz-cachyos instead of /@/boot/vmlinuz-cachyos, that’s the bug. And grub-mkrelpath will tell us whether grub-mkconfig can detect the subvolume correctly or if we need to fix the detection.

After not selecting anything in GRUB, I ended up in a terminal mode.

I am currently logged in as root@machine ~]#.

Can you think of anything else that could be done there? Otherwise, back to Live…

Thank you for your instructions @thedarkbird

After tinkering with it for hours, i finally got a working solution.

This also might be interesting for you @SHINE

So the instructions got a few problems:

  1. /etc/crypttab (the system one, not .initramfs) will contain an old Calamares entry.
    The initramfs already handles unlocking via crypttab.initramfs, systemd doesn’t need to do anything there. The real /etc/crypttab entry is purely a leftover from Calamares and serves no purpose in the setup.

So, what i’ve done is i did comment out the old Calamares entry in /etc/crypttab so the file looks like this:

# <name> <device> <password> <options>
# luks-<My_Luks_UUID> UUID=<My_Luks_UUID> /crypto_keyfile.bin luks

  1. The container opens fine as cryptroot, but Calamares wrote /etc/fstab using its own device mapper name luks-934b2f-.... That device never gets created anymore, the setup creates cryptroot instead. So systemd waits forever for a device that will never appear.

The solution is to chroot into the installation as in your instructions
and then:

cat /etc/fstab

You’ll see lines referencing luks-934b2f-....
Replace every occurrence with /dev/mapper/cryptroot:

like for example with:

sed -i 's|/dev/mapper/luks-<Your_Luks_UUID>|/dev/mapper/cryptroot|g' /etc/fstab

Then verify it looks correct:

cat /etc/fstab

All your Btrfs subvolume mount entries (/, /home, /var/log, etc.) should now point to /dev/mapper/cryptroot.

Also, no initramfs rebuild is needed.

After that, it boots just fine into CachyOS, without stopping at rescue mode shell.
So, i asked Claude to rewrite your Instructions, but considering everything i just wrote.

Here’s the new Tutorial:

CachyOS Full Disk Encryption with Encrypted /boot (LUKS2 + GRUB)

Applies to: CachyOS, dual-boot alongside Windows, UEFI systems, NVMe SSDs
Goal: Encrypt the entire Linux partition including /boot inside a LUKS2 container, with GRUB unlocking it at boot (single passphrase prompt).


Overview

This guide sets up the following:

  • A dedicated Linux ESP (unencrypted, for GRUB itself)

  • A LUKS2 container holding a Btrfs root filesystem (with all subvolumes, including /boot)

  • GRUB unlocks the container at boot with a passphrase

  • A keyfile embedded in the initramfs avoids a second password prompt from the initramfs


Partition Layout

# Size Type Purpose
p1 ~100 MiB EFI System Windows ESP
p2 ~16 MiB Microsoft Reserved Windows internal
p3 varies NTFS Windows (C:)
p4 ~500 MiB NTFS / WinRE Windows Recovery
p5 512 MiB EFI System Linux ESP (new)
p6 remaining Linux filesystem LUKS2 container (new)

Adjust partition numbers to match your actual disk layout.


Step 1 — Create the Linux Partitions

Boot the CachyOS live USB.

If you still need to shrink Windows, do it from Windows first (Disk Management).

Then create the two new partitions using KDE Partition Manager (pre-installed on CachyOS — search for “Partition Manager” in the app menu) or GParted if you prefer:

  1. Open KDE Partition Manager and select your SSD from the left panel.

  2. Click on the unallocated free space, then New:

    • Size: 512 MiB

    • File system: FAT32

    • Partition type: GPT → EFI System Partition

    • Label: Linux ESP (optional but helpful)

  3. Click on the remaining unallocated space, then New:

    • Size: all remaining space

    • File system: ext4 (doesn’t matter — Calamares will overwrite it)

    • Partition type: Linux filesystem

  4. Click Apply to write the changes to disk.

Do not manually encrypt or further format p6 — Calamares will handle it.


Step 2 — Install with Calamares

Launch the CachyOS installer. Proceed through language and locale setup.

Bootloader screen: Select GRUB (not systemd-boot).

Partitioning screen — choose Manual Partitioning:

  • Select /dev/nvme0n1p5:

    • Mount point: /boot/efi

    • Filesystem: FAT32

    • Format or leave as-is (already formatted)

  • Select /dev/nvme0n1p6:

    • Mount point: /

    • Filesystem: Btrfs

    • Check Encrypt, set your passphrase

  • Leave all Windows partitions untouched.

Re-attempt note: If p6 already has a LUKS header from a previous install attempt, Calamares may not let you set a new password. In that case, delete and recreate the partition in Calamares or wipe it with GParted first.

Continue through user creation and let the installation complete.

Do NOT reboot yet.


Step 3 — Identify Your LUKS UUID

sudo blkid /dev/nvme0n1p6

Note the UUID="..." value — this is your <LUKS-UUID>. It looks like: 84d2f318-ed45-4d5f-9f63-71f0b9695df2

Important: Replace <LUKS-UUID> with your actual UUID throughout this guide. Do not type the angle brackets <>.


Step 4 — Convert the KDF from Argon2id to PBKDF2

GRUB cannot unlock a LUKS2 container if any active key slot uses Argon2id. Calamares defaults to Argon2id, so this must be converted.

First, close the container if Calamares left it open:

sudo umount -R /tmp/calamares-root-* 2>/dev/null
sudo cryptsetup close luks-<LUKS-UUID>

If it’s still busy, check lsblk for leftover mounts and unmount them, then retry.

Alternative: If you cannot close the container no matter what, simply reboot back into the CachyOS live USB. The container will be closed cleanly on reboot, and you can proceed from Step 4 without any leftover mounts to worry about.

Convert the key slot:

sudo cryptsetup luksConvertKey --pbkdf pbkdf2 /dev/nvme0n1p6
# Enter your passphrase when prompted.

Verify — every active slot must show pbkdf2:

sudo cryptsetup luksDump /dev/nvme0n1p6

If Calamares created an additional unknown key slot (e.g. slot 1 with argon2id), remove it:

sudo cryptsetup luksKillSlot /dev/nvme0n1p6 1
# Confirm with your passphrase on slot 0.


Step 5 — Mount and Chroot into the Installed System

sudo cryptsetup open /dev/nvme0n1p6 cryptroot

sudo mount -o subvol=@,compress=zstd /dev/mapper/cryptroot /mnt
sudo mount -o subvol=@home,compress=zstd /dev/mapper/cryptroot /mnt/home
sudo mount -o subvol=@root,compress=zstd /dev/mapper/cryptroot /mnt/root
sudo mount -o subvol=@srv,compress=zstd /dev/mapper/cryptroot /mnt/srv
sudo mount -o subvol=@cache,compress=zstd /dev/mapper/cryptroot /mnt/var/cache
sudo mount -o subvol=@log,compress=zstd /dev/mapper/cryptroot /mnt/var/log
sudo mount -o subvol=@tmp,compress=zstd /dev/mapper/cryptroot /mnt/var/tmp

sudo mount /dev/nvme0n1p5 /mnt/boot/efi

sudo mount --bind /dev /mnt/dev
sudo mount --bind /dev/pts /mnt/dev/pts
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys
sudo mount --bind /sys/firmware/efi/efivars /mnt/sys/firmware/efi/efivars

sudo chroot /mnt


Step 6 — Fix /etc/fstab :warning:

This is a critical step that Calamares gets wrong.

Calamares writes /etc/fstab using its own internal device mapper name (/dev/mapper/luks-<UUID>), but your setup maps the container as cryptroot. If left uncorrected, the system will hang at boot waiting for a device that never appears.

Fix it now:

sed -i 's|/dev/mapper/luks-<LUKS-UUID>|/dev/mapper/cryptroot|g' /etc/fstab

Verify the result — every Btrfs subvolume line should reference /dev/mapper/cryptroot:

cat /etc/fstab


Step 7 — Fix /etc/crypttab :warning:

Another critical step. Calamares leaves a broken entry here too.

Calamares writes /etc/crypttab with a reference to /crypto_keyfile.bin — a file that won’t exist in your final setup. This causes a “Key data incorrect” error and an “Already in use” error at every boot.

Open the file:

nano /etc/crypttab

You will see something like:

luks-<LUKS-UUID>  UUID=<LUKS-UUID>  /crypto_keyfile.bin  luks

Comment out that entire line by adding a # at the start:

# luks-<LUKS-UUID>  UUID=<LUKS-UUID>  /crypto_keyfile.bin  luks

The initramfs handles unlocking via /etc/crypttab.initramfs — systemd does not need to do anything here.


Step 8 — Configure the Initramfs Hooks

grep "^HOOKS" /etc/mkinitcpio.conf

Ensure the HOOKS line uses the systemd-based stack and includes sd-encrypt:

HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)

If sd-encrypt is missing, add it. Do not mix systemd with encrypt, or udev with sd-encrypt.


Step 9 — Create a Keyfile (Avoid Double Password Prompt)

Without this, GRUB prompts for the passphrase to read the kernel, and then the initramfs prompts again to mount root. The keyfile lets the initramfs unlock automatically — it’s safe because the keyfile lives inside the encrypted volume.

mkdir -p /etc/cryptsetup-keys.d
dd bs=512 count=4 if=/dev/random iflag=fullblock | \
  install -m 0600 /dev/stdin /etc/cryptsetup-keys.d/cryptroot.key

# Add the keyfile to LUKS — must use pbkdf2 so GRUB can still unlock it:
cryptsetup luksAddKey --pbkdf pbkdf2 /dev/nvme0n1p6 /etc/cryptsetup-keys.d/cryptroot.key

Add the keyfile to the initramfs. Edit /etc/mkinitcpio.conf and find the FILES= line:

FILES=(/etc/cryptsetup-keys.d/cryptroot.key)

Configure the initramfs to use it. Edit /etc/crypttab.initramfs (not /etc/crypttab):

cryptroot    UUID=<LUKS-UUID>    /etc/cryptsetup-keys.d/cryptroot.key    luks

The volume name cryptroot must match the keyfile name cryptroot.key — systemd auto-detects keyfiles in /etc/cryptsetup-keys.d/ by this naming convention. This name must also match what you use in Steps 5 and 10.


Step 10 — Configure GRUB

Edit /etc/default/grub:

nano /etc/default/grub

Make sure these two settings are correct:

GRUB_ENABLE_CRYPTODISK=y

GRUB_CMDLINE_LINUX_DEFAULT='nowatchdog nvme_load=YES zswap.enabled=0 rd.luks.name=<LUKS-UUID>=cryptroot splash loglevel=3'

Important rules for the cmdline:

  • :white_check_mark: Use rd.luks.name=<UUID>=cryptroot — this names the mapper cryptroot

  • :cross_mark: Do not use rd.luks.uuid= — that would name the mapper luks-<UUID>, breaking the keyfile auto-detection and fstab

  • :cross_mark: Do not include rd.luks.key= — the keyfile is handled via crypttab.initramfs

If there is a separate GRUB_CMDLINE_LINUX="" line, leave it empty.


Step 11 — Regenerate Initramfs and GRUB

mkinitcpio -P

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=CachyOS

grub-mkconfig -o /boot/grub/grub.cfg

Verify the GRUB config references cryptodisk:

grep -i cryptodisk /boot/grub/grub.cfg

If that returns lines, GRUB is correctly configured.


Step 12 — Exit and Reboot

exit

sudo umount -R /mnt
sudo cryptsetup close cryptroot
sudo reboot

Remove the live USB. GRUB will prompt for your passphrase once, then the system boots fully automatically — no second prompt, no errors.


What Calamares Gets Wrong (Summary)

For anyone debugging a broken install, these are the three things Calamares leaves in a broken state when using this setup:

File Calamares leaves Correct value
/etc/fstab /dev/mapper/luks-<UUID> /dev/mapper/cryptroot
/etc/crypttab Active entry with /crypto_keyfile.bin Comment the line out entirely
GRUB_CMDLINE_LINUX_DEFAULT May include rd.luks.key=/crypto_keyfile.bin Remove that parameter

All three must be corrected for a clean boot.

So restart from step 6?

You could try to boot into the live system and start at step five, if you’re only able to boot into the rescue shell up to this point.

— grep ‘linux /’ /boot/grub/grub.cfg

: No such file

— nano /boot/grub/grub.cfg

: (Shows an empty file)

_______________________________________

¿ sudo or chroot?

— = commands

: = returns

¿ = comments / question

_______________________________________

— grub-mkrelpath /boot/vmlinuz-cachyos

: failed to get canonical path

— sudo nano /etc/crypttab

: Notes: Do not set your root partition here, it must be set up beforehand by the initramfs (/etc/mkinitcpio.conf).

Lists 5 devices: home | (uuid) | password 1; data1 | (sda 3 / windata | password 2; (rest).

I hadn’t decrypted the container yet.

Dolphin shows it to me and offers to decrypt it.

I’ll root myself again according to step 5.

6, 7 and 8, 9 and 10 done.

The following sentence is unclear:

“The volume name cryptroot must match the keyfile name cryptroot.key — systemd auto-detects keyfiles in /etc/cryptsetup-keys.d/ by this naming convention. This name must also match what you use in Steps 5 and 10.”

Also: Do the UUIDs from steps 6 and 9 have to be those of nvme0n1p6 or the cryptroot below it?

Seems to have worked, thank you very much!

I guess Steps 6 & 7 fixed it, as :warning: highlighted.

So, I’ve become somewhat acclimated to Niri

and am wondering how to proceed

with the remaining steps

(Secure Boot & Bitlocker).

Step 11 (lsinitcpio) failed with “no such file”.