cd /news/open-source/limine-luks2-tpm2-auto-unlock-guide-… Β· home β€Ί topics β€Ί open-source β€Ί article
[ARTICLE Β· art-11168] src=gist.github.com β†— pub= topic=open-source verified=true sentiment=Β· neutral

Limine + LUKS2 + TPM2 Auto-Unlock Guide (CachyOS/Arch Linux)

This article provides a step-by-step guide for configuring automatic LUKS2 root partition decryption using a TPM2 chip on Arch Linux or CachyOS systems using the Limine bootloader and dracut. The process involves installing necessary packages, configuring dracut modules and crypttab, switching kernel parameters from mkinitcpio to dracut syntax, and then enrolling a TPM2 key bound to PCRs 0 and 7 after verifying that password-based boot still works. The guide emphasizes verifying each configuration step and warns against proceeding with TPM enrollment if the system does not boot correctly with a password first.

read5 min views21 publishedNov 19, 2025

Working configuration for:

  • Limine boot
  • LUKS2 encrypted root partition
  • btrfs with Snapper snapshots
- dracut (required for btrfs snapshot boot)
- systemd-based initramfs
  • Secure Boot enabled
  • TPM2 auto-unlock using PCR 0+7 Verify your current setup: Verify LUKS2 (not LUKS1): sudo cryptsetup luksDump /dev/nvme1n1p2 | grep Version Expected output: Version: 2 Verify btrfs: df -Th / Expected output (look for "btrfs"): Filesystem Type Size Used Avail Use% Mounted on /dev/mapper/luks-3d2966af-234b-424e-a81d-570f9d2299ad btrfs 1.9T 606G 1.3T 33% / Verify snapper is configured: snapper list-configs Expected output: Config β”‚ Subvolume ───────┼────────── root β”‚ / Verify TPM2 is available: systemd-cryptenroll --tpm2-device=list Expected output: PATH DEVICE DRIVER /dev/tpmrm0 MSFT0101:00 tpm_crb
sudo pacman -S dracut tpm2-tss tpm2-tools
paru -S limine-dracut-support
sudo pacman -R limine-mkinitcpio-hook
Note: limine-dracut-support
and limine-mkinitcpio-hook

conflict and cannot coexist. Create /etc/dracut.conf.d/tpm.conf : sudo nano /etc/dracut.conf.d/tpm.conf Add this line: add_dracutmodules+=" tpm2-tss " Create /etc/dracut.conf.d/cryptsetup.conf : sudo nano /etc/dracut.conf.d/cryptsetup.conf

Add this line (fixes missing TPM2 token library):
install_items+=" /usr/lib/cryptsetup/libcryptsetup-token-systemd-tpm2.so "

Verify the files: cat /etc/dracut.conf.d/tpm.conf cat /etc/dracut.conf.d/cryptsetup.conf Expected output:

add_dracutmodules+=" tpm2-tss "
install_items+=" /usr/lib/cryptsetup/libcryptsetup-token-systemd-tpm2.so "

Edit /etc/crypttab : sudo nano /etc/crypttab Change from: luks-<UUID> UUID=<UUID> none To: luks-<UUID> UUID=<UUID> - tpm2-device=auto Example: luks-3d2966af-234b-424e-a81d-570f9d2299ad UUID=3d2966af-234b-424e-a81d-570f9d2299ad - tpm2-device=auto Verify: cat /etc/crypttab

Expected output (look for -
and tpm2-device=auto
):
luks-3d2966af-234b-424e-a81d-570f9d2299ad UUID=3d2966af-234b-424e-a81d-570f9d2299ad - tpm2-device=auto

Edit /etc/default/limine : sudo nano /etc/default/limine

Change from (mkinitcpio syntax):
KERNEL_CMDLINE[default]+="... cryptdevice=UUID=<UUID>:<mapper-name> ..."
To (dracut syntax):
KERNEL_CMDLINE[default]+="... rd.luks.name=<UUID>=<mapper-name> ..."

Example: KERNEL_CMDLINE[default]+="quiet nowatchdog splash rw rootflags=subvol=/@ rd.luks.name=3d2966af-234b-424e-a81d-570f9d2299ad=luks-3d2966af-234b-424e-a81d-570f9d2299ad root=/dev/mapper/luks-3d2966af-234b-424e-a81d-570f9d2299ad" Verify: cat /etc/default/limine Expected output (look for rd.luks.name= instead of cryptdevice= ): ESP_PATH="/boot" KERNEL_CMDLINE[default]+="quiet nowatchdog splash rw rootflags=subvol=/@ rd.luks.name=3d2966af-234b-424e-a81d-570f9d2299ad=luks-3d2966af-234b-424e-a81d-570f9d2299ad root=/dev/mapper/luks-3d2966af-234b-424e-a81d-570f9d2299ad" BOOT_ORDER="*, *lts, *fallback, Snapshots" sudo limine-dracut This will:

  • Generate new initramfs with dracut
  • Update Limine boot entries
  • Apply new kernel parameters Expected output: dracut: Executing: /usr/bin/dracut --force --hostonly ... dracut: *** Including module: systemd ***
dracut: *** Including module: tpm2-tss ***
dracut: *** Including module: crypt ***

... dracut: *** Creating initramfs image file done *** sudo reboot IMPORTANT: You should still be prompted for your LUKS password. Verify:

  • System boots correctly
  • Password unlock works
  • System fully boots to desktop If this fails, DO NOT PROCEED. Fix boot issues before enrolling TPM. After confirming password boot works: Verify TPM is detected: systemd-cryptenroll --tpm2-device=list Expected output: PATH DEVICE DRIVER /dev/tpmrm0 MSFT0101:00 tpm_crb Enroll TPM key (replace /dev/nvme1n1p2
with your LUKS partition):
sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/nvme1n1p2

Expected output: πŸ” Please enter current passphrase for disk /dev/nvme1n1p2: **** New TPM2 token enrolled as key slot 1. PCR Explanation:

- PCR 0: UEFI firmware code
- PCR 7: Secure Boot state

Verify enrollment: sudo systemd-cryptenroll /dev/nvme1n1p2 Expected output: SLOT TYPE 0 password 1 tpm2 Also verify token: sudo cryptsetup luksDump /dev/nvme1n1p2 | grep -A 5 "Tokens:" Expected output: Tokens:

0: systemd-tpm2
tpm2-hash-pcrs: 0+7
tpm2-pcr-bank: sha256
tpm2-pubkey:
(null)

sudo limine-dracut Expected output:

dracut: Executing: /usr/bin/dracut --force --hostonly ...
dracut: *** Including module: tpm2-tss ***

... dracut: *** Creating initramfs image file done *** sudo reboot Expected behavior:

  • System boots to Limine
  • LUKS partition automatically unlocks (no password prompt)
  • System boots normally
If TPM unlock fails:
- You'll be prompted for password (fallback still works)
  • System is NOT bricked Check TPM enrollment: sudo systemd-cryptenroll /dev/nvme1n1p2 Expected output: SLOT TYPE 0 password 1 tpm2 Check LUKS keyslots: sudo cryptsetup luksDump /dev/nvme1n1p2 Expected output (look for Token 0: systemd-tpm2 and Keyslot 1): LUKS header information Version: 2 ... Tokens:
0: systemd-tpm2
tpm2-hash-pcrs: 0+7
tpm2-pcr-bank: sha256

... Keyslots: 0: luks2 Key: 512 bits ... 1: luks2 Key: 512 bits ... Verify dracut includes TPM modules: lsinitrd | grep tpm2

Expected output (should show TPM-related files):
-rw-r--r-- 1 root root 123456 Nov 19 18:53 usr/lib/systemd/system-generators/systemd-tpm2-generator
drwxr-xr-x 3 root root 0 Nov 19 18:53 usr/lib/cryptsetup
-rwxr-xr-x 1 root root 98765 Nov 19 18:53 usr/lib/cryptsetup/libcryptsetup-token-systemd-tpm2.so

Check journal for errors:

sudo journalctl -b | grep -i tpm
sudo journalctl -b | grep -i crypt

Look for errors like: libcryptsetup-token-systemd-tpm2.so: cannot open shared object file

  • Missing cryptsetup libraryFailed to unseal
  • PCR values changedTPM2 token not found
  • Enrollment failed Common causes:
  • Missing cryptsetup library - verify /etc/dracut.conf.d/cryptsetup.conf
- PCR values changed (firmware update) - re-enroll TPM key
- Secure Boot state changed - re-enroll TPM key

PCR values change when:

  • Firmware/BIOS updated
  • Secure Boot keys changed
  • Boot configuration modified
Solution - Re-enroll TPM:
sudo systemd-cryptenroll --wipe-slot=tpm2 /dev/nvme1n1p2
sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/nvme1n1p2

sudo limine-dracut sudo systemd-cryptenroll --wipe-slot=tpm2 /dev/nvme1n1p2 sudo limine-dracut Password unlock continues to work. List TPM devices: systemd-cryptenroll --tpm2-device=list Expected output: PATH DEVICE DRIVER /dev/tpmrm0 MSFT0101:00 tpm_crb Check TPM in sysfs: cat /sys/class/tpm/tpm0/device/description Expected output: TPM 2.0 Device Check dmesg for TPM: sudo dmesg | grep -i tpm

Expected output (should show TPM initialization):
[ 0.614715] tpm_crb MSFT0101:00: Disabling hwrng
  • Password always works - TPM is convenience, not a replacement for your password
- Snapshots remain bootable - With
limine-snapper-sync
, btrfs snapshots work with TPM - PCR selection trade-offs:
- PCR 0+7 (recommended): Survives most updates, secure
  • PCR 0+2+7: More secure, may break on boot config changes
  • PCR 7 only: Most flexible, least secure
  • Secure Boot required - PCR 7 measures Secure Boot state
  • Recovery is safe - Password fallback always available For systems with btrfs snapshots (using Snapper/Timeshift), dracut is required because:
  • mkinitcpio's systemd hook is incompatible with btrfs-overlayfs
  • dracut properly supports bootable snapshot entries via
limine-snapper-sync
If you don't use btrfs snapshots, you can use the simpler mkinitcpio path.

Tested on:

- CachyOS (Arch-based)
- Limine 10.3.0-1
- dracut 109-1
- systemd 258.2-2
- Kernel: linux-cachyos 6.17.8-2
- Hardware: ASUS ROG with Intel PTT (TPM 2.0)
── more in #open-source 4 stories Β· sorted by recency
── more on @limine 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/limine-luks2-tpm2-au…] indexed:0 read:5min 2025-11-19 Β· β€”