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

@witchbutter
Copy link

witchbutter commented Feb 16, 2026

Had an error at dracut after updating all crypttab and /etc/default/limine: /usr/bin/dracut: line 3107: cpio: command not found /usr/bin/dracut: line 3171: cpio: command not found dracut[F]: Creation of /tmp/staging_initramfs.img failed -- oddly cpio was not installed by default, worked after installing.

Also verification lsinitrd command could not work on my system without exactly specifying the file using sudo: ❯ sudo lsinitrd /boot/hasheddirectory/linux-cachyos-rt-bore/initramfs-linux-cachyos-rt-bore | grep tpm2 tpm2-tss -rwxr-xr-x 1 root root 742600 Sep 13 2024 usr/bin/tpm2 lrwxrwxrwx 1 root root 4 Feb 15 13:01 usr/bin/tpm2_createpolicy -> tpm2 lrwxrwxrwx 1 root root 4 Feb 15 13:01 usr/bin/tpm2_createprimary -> tpm2 lrwxrwxrwx 1 root root 4 Feb 15 13:01 usr/bin/tpm2_create -> tpm2 lrwxrwxrwx 1 root root 4 Feb 15 13:01 usr/bin/tpm2_load -> tpm2 lrwxrwxrwx 1 root root 4 Feb 15 13:01 usr/bin/tpm2_pcrextend -> tpm2 lrwxrwxrwx 1 root root 4 Feb 15 13:01 usr/bin/tpm2_pcrread -> tpm2 lrwxrwxrwx 1 root root 4 Feb 15 13:01 usr/bin/tpm2_unseal -> tpm2 -rwxr-xr-x 1 root root 30776 Feb 6 10:03 usr/lib/cryptsetup/libcryptsetup-token-systemd-tpm2.so -rwxr-xr-x 1 root root 14360 Feb 6 10:03 usr/lib/systemd/system-generators/systemd-tpm2-generator -rw-r--r-- 1 root root 567 Feb 6 10:03 usr/lib/systemd/system/tpm2.target -rw-r--r-- 1 root root 89 Oct 20 2024 usr/lib/sysusers.d/tpm2-tss.conf -rw-r--r-- 1 root root 592 Oct 20 2024 usr/lib/tmpfiles.d/tpm2-tss-fapi.conf

This is an exceptionally good guide, thank you so much!

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