Skip to content

Instantly share code, notes, and snippets.

@zerofltexx
Created November 19, 2025 13:53
Show Gist options
  • Select an option

  • Save zerofltexx/d75168b7d2a0b146a5a6e13a397acf07 to your computer and use it in GitHub Desktop.

Select an option

Save zerofltexx/d75168b7d2a0b146a5a6e13a397acf07 to your computer and use it in GitHub Desktop.
Limine + LUKS2 + TPM2 Auto-Unlock Guide (CachyOS/Arch Linux)

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

Working configuration for:

  • Limine bootloader
  • 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

Prerequisites

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

Step 1: Install Required Packages

# Install from official repos
sudo pacman -S dracut tpm2-tss tpm2-tools

# Install from AUR
paru -S limine-dracut-support

Step 2: Remove Conflicting Package

sudo pacman -R limine-mkinitcpio-hook

Note: limine-dracut-support and limine-mkinitcpio-hook conflict and cannot coexist.

Step 3: Configure Dracut for TPM2

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 "

Step 4: Update /etc/crypttab

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

Step 5: Update Kernel Parameters for Dracut

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"

Step 6: Generate Initial Dracut Initramfs

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 ***

Step 7: Test Boot with Password (Critical!)

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.

Step 8: Enroll TPM2 Key

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)

Step 9: Regenerate Initramfs with TPM Key

sudo limine-dracut

Expected output:

dracut: Executing: /usr/bin/dracut --force --hostonly ...
dracut: *** Including module: tpm2-tss ***
...
dracut: *** Creating initramfs image file done ***

Step 10: Test TPM Auto-Unlock

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

Verification Commands

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

Troubleshooting

TPM unlock fails, prompts for password

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 library
  • Failed to unseal - PCR values changed
  • TPM2 token not found - Enrollment failed

Common causes:

  1. Missing cryptsetup library - verify /etc/dracut.conf.d/cryptsetup.conf
  2. PCR values changed (firmware update) - re-enroll TPM key
  3. Secure Boot state changed - re-enroll TPM key

PCR values changed after firmware/BIOS update

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

Remove TPM auto-unlock

sudo systemd-cryptenroll --wipe-slot=tpm2 /dev/nvme1n1p2
sudo limine-dracut

Password unlock continues to work.

Check TPM device status

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

Important Notes

  1. Password always works - TPM is convenience, not a replacement for your password
  2. Snapshots remain bootable - With limine-snapper-sync, btrfs snapshots work with TPM
  3. 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
  4. Secure Boot required - PCR 7 measures Secure Boot state
  5. Recovery is safe - Password fallback always available

Why Dracut Instead of mkinitcpio?

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.

System Information

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)

References

@FourGL
Copy link

FourGL commented Jan 25, 2026

Works perfect on the first 2026 release.
Thank U!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment