Linuxpad

Got Linux?

Gentoo Linux Installation Guide: Encrypted Btrfs with OpenRC, EFI Stub, Secure Boot & TPM

Gentoo Linux Installation Guide: Encrypted Btrfs with OpenRC, EFI Stub, Secure Boot & TPM

Target audience: Intermediate–advanced Linux users.
Features: Full disk encryption (LUKS2), Btrfs with subvolumes, OpenRC init, EFI stub boot, Secure Boot (with custom keys), TPM2 auto-unlock via Clevis.
Based onGentoo WikiArch Wiki, and personal tweaks.

Now let us get started!!

1. Preparation & Boot

  • Boot from a valid Gentoo ISO (download).
  • Configure your network – the ISO usually gets DHCP automatically.
    If needed, follow the Gentoo Handbook Networking.
  • Optional but recommended: start SSH daemon so you can copy-paste commands from another machine
rc-service sshd start
passwd  # set a root password

2. UEFI Partition Layout

We'll use cfdisk on your main drive (e.g., /dev/nvme0n1).

PartitionSizeTypeLabel
/dev/nvme0n1p11 GiBEFI SystemGentooBoot
/dev/nvme0n1p2restLinux filesystem(will be LUKS)
cfdisk /dev/nvme0n1

Example layout:

Device          Start       End         Sectors    Size   Type
/dev/nvme0n1p1  882423808   884520959   2097152    1G     EFI System
/dev/nvme0n1p2  34816       629198847   629164032  300G   Linux filesystem


⚠️ Adjust partition numbers and sizes to your drive.

3. Encryption (LUKS2)

We encrypt the root partition (/dev/nvme0n1p2) with strong LUKS2 parameters.

cryptsetup luksFormat --type luks2 \
  --cipher aes-xts-plain64 --key-size 512 \
  --pbkdf argon2id --pbkdf-memory 1048576 --iter-time 4000 \
  --label "GentooLuks" /dev/nvme0n1p2

cryptsetup open /dev/nvme0n1p2 root



Now the decrypted device is /dev/mapper/root.

4. Btrfs Filesystem & Subvolumes

Create filesystems:

mkfs.vfat -n GentooBoot -F 32 /dev/nvme0n1p1
mkfs.btrfs -L GentooRoot /dev/mapper/root

Mount the root Btrfs volume and create subvolumes:

mkdir -p /mnt/gentoo
mount LABEL=GentooRoot /mnt/gentoo/

btrfs subvolume create /mnt/gentoo/@
btrfs subvolume create /mnt/gentoo/@home
btrfs subvolume create /mnt/gentoo/@.snapshots
btrfs subvolume create /mnt/gentoo/@usr
btrfs subvolume create /mnt/gentoo/@opt
btrfs subvolume create /mnt/gentoo/@srv
btrfs subvolume create /mnt/gentoo/@db
btrfs subvolume create /mnt/gentoo/@log
btrfs subvolume create /mnt/gentoo/@tmp
btrfs subvolume create /mnt/gentoo/@crash
btrfs subvolume create /mnt/gentoo/@spool
btrfs subvolume create /mnt/gentoo/@portage
btrfs subvolume create /mnt/gentoo/@NetworkManager
btrfs subvolume create /mnt/gentoo/@binpkgs
btrfs subvolume create /mnt/gentoo/@distfiles
btrfs subvolume create /mnt/gentoo/@boot

umount -l /mnt/gentoo

Now mount each subvolume to its final location:

mount -o subvol=@ LABEL=GentooRoot /mnt/gentoo

mkdir -p /mnt/gentoo/{home,.snapshots,usr,opt,srv,boot,efi,var/{db,log,tmp,crash,spool,lib/{portage,NetworkManager},cache/{binpkgs,distfiles}}}

mount -o subvol=@home      LABEL=GentooRoot /mnt/gentoo/home
mount -o [email protected] LABEL=GentooRoot /mnt/gentoo/.snapshots
mount -o subvol=@usr       LABEL=GentooRoot /mnt/gentoo/usr
mount -o subvol=@opt       LABEL=GentooRoot /mnt/gentoo/opt
mount -o subvol=@srv       LABEL=GentooRoot /mnt/gentoo/srv
mount -o subvol=@db        LABEL=GentooRoot /mnt/gentoo/var/db
mount -o subvol=@log       LABEL=GentooRoot /mnt/gentoo/var/log
mount -o subvol=@tmp       LABEL=GentooRoot /mnt/gentoo/var/tmp
mount -o subvol=@crash     LABEL=GentooRoot /mnt/gentoo/var/crash
mount -o subvol=@spool     LABEL=GentooRoot /mnt/gentoo/var/spool
mount -o subvol=@portage   LABEL=GentooRoot /mnt/gentoo/var/lib/portage
mount -o subvol=@NetworkManager LABEL=GentooRoot /mnt/gentoo/var/lib/NetworkManager
mount -o subvol=@binpkgs   LABEL=GentooRoot /mnt/gentoo/var/cache/binpkgs
mount -o subvol=@distfiles LABEL=GentooRoot /mnt/gentoo/var/cache/distfiles
mount -o subvol=@boot      LABEL=GentooRoot /mnt/gentoo/boot
mount LABEL=GentooBoot /mnt/gentoo/efi

📁 Why so many subvolumes? It gives flexibility for snapshots (e.g., you can snapshot @ and @home separately) and fine-grained mount options (e.g., nodev,noexec for /var/db).

5. Download Stage3 & Verify

Download a hardened OpenRC stage3 (LLVM/musl stages may not work with these instructions).

cd /mnt/gentoo
wget stage3-amd64-hardened-openrc-2025XXXX.tar.xz
wget stage3-amd64-hardened-openrc-2025XXXX.tar.xz.asc

gpg --import /usr/share/openpgp-keys/gentoo-release.asc
gpg --verify stage3-amd64-*.tar.xz.asc

Once verified, extract:

tar xpvf stage3-*.tar.xz --xattrs-include='*.*' --numeric-owner -C /mnt/gentoo

6. Portage Configuration

Edit /mnt/gentoo/etc/portage/make.conf:

COMMON_FLAGS="-march=native -O2 -pipe"
ACCEPT_LICENSE="*"
FEATURES="${FEATURES} getbinpkg binpkg-request-signature"

Copy DNS info into the chroot:

cp --dereference /etc/resolv.conf /mnt/gentoo/etc/

7. Chroot & System Setup

Mount the virtual filesystems and enter the chroot:

mount --types proc /proc /mnt/gentoo/proc
mount --rbind /sys /mnt/gentoo/sys && mount --make-rslave /mnt/gentoo/sys
mount --rbind /dev /mnt/gentoo/dev && mount --make-rslave /mnt/gentoo/dev
mount --bind /run /mnt/gentoo/run && mount --make-slave /mnt/gentoo/run

chroot /mnt/gentoo /bin/bash
source /etc/profile
export PS1="(chroot) ${PS1}"

Now inside chroot:

# Get latest repository snapshot
emerge-webrsync

# Setup binary package host (getuto = Gentoo's binary package service)
getuto

# Choose fastest mirrors
emerge --ask --verbose --oneshot app-portage/mirrorselect
mirrorselect -i -o >> /etc/portage/make.conf

# Full sync
emerge --sync

# Select profile (hardened OpenRC)
eselect profile list
eselect profile set 21   # adjust number to your choice

# CPU optimizations
emerge --ask --oneshot app-portage/cpuid2cpuflags
echo "*/* $(cpuid2cpuflags)" > /etc/portage/package.use/00cpu-flags

# Update @world
emerge -avuDUg @world

# Cleanup
emerge --ask --depclean

# Install a text editor
emerge --ask app-editors/nano

Locale & Timezone

echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
eselect locale set en_US.utf8

ln -sf /usr/share/zoneinfo/YourRegion/City /etc/localtime

env-update && source /etc/profile && export PS1="(chroot) ${PS1}"

8. Kernel, Initramfs & EFI Stub Boot

We'll use the distribution kernel (gentoo-kernel-bin) with dracut for initramfs.

# Use dracut with installkernel
echo "sys-kernel/installkernel dracut" >> /etc/portage/package.use/installkernel

# Required packages
emerge --ask sys-kernel/linux-firmware sys-firmware/sof-firmware \
  sys-fs/btrfs-progs sys-fs/cryptsetup sys-kernel/installkernel

# Configure dracut
echo 'hostonly="yes"' >> /etc/dracut.conf
echo 'hostonly_mode=strict' >> /etc/dracut.conf
echo 'add_dracutmodules+=" crypt "' >> /etc/dracut.conf

# Install kernel
emerge --ask sys-kernel/gentoo-kernel-bin
echo 'USE="dist-kernel"' >> /etc/portage/make.conf

Configure /etc/fstab

Create an extensive fstab – here’s a shortened version (full one in your tutorial).
Example entry for root:

LABEL=GentooRoot / btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@ 0 0
LABEL=GentooRoot /home btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@home 0 0
LABEL=GentooRoot /.snapshots btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@.snapshots	0 0
LABEL=GentooRoot /usr btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@usr	0 0
LABEL=GentooRoot /opt btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@opt 0 0
LABEL=GentooRoot /srv btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@srv 0 0
LABEL=GentooRoot /var/db btrfs rw,nosuid,nodev,noexec,noatime,lazytime,skip_balance,ssd,discard,space_cache=v2,compress-force=zstd:10,commit=120,subvol=/@db	0 0
LABEL=GentooRoot /var/log btrfs rw,nosuid,nodev,noexec,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@log	0 0
LABEL=GentooRoot /var/tmp btrfs rw,nosuid,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@tmp	0 0
LABEL=GentooRoot /var/crash btrfs rw,nosuid,nodev,noexec,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@crash	0 0
LABEL=GentooRoot /var/spool btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@spool 0 0
LABEL=GentooRoot /var/lib/portage btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@portage 0 0
LABEL=GentooRoot /var/lib/NetworkManager btrfs rw,nodev,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@NetworkManager 0 0
LABEL=GentooRoot /var/cache/binpkgs btrfs rw,nosuid,nodev,noexec,noatime,lazytime,skip_balance,ssd,discard,space_cache=v2,compress-force=zstd:10,commit=120,subvol=/@binpkgs 0 0
LABEL=GentooRoot /var/cache/distfiles btrfs rw,nosuid,nodev,noexec,noatime,lazytime,skip_balance,ssd,discard,space_cache=v2,compress-force=zstd:10,commit=120,subvol=/@distfiles 0 0
LABEL=GentooRoot /boot btrfs rw,nosuid,nodev,noexec,noatime,lazytime,skip_balance,nodatacow,ssd,discard,space_cache=v2,commit=120,subvol=/@boot 0 0
LABEL=GentooBoot /efi vfat rw,nosuid,nodev,noexec,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=ascii,shortname=mixed,utf8,discard,flush,errors=remount-ro	0 2

EFI Stub Boot with installkernel

mkdir -p /efi/EFI/Gentoo

# Enable efistub in installkernel
echo "sys-kernel/installkernel efistub" >> /etc/portage/package.use/installkernel

# Rebuild installkernel
emerge sys-kernel/installkernel

# Generate initramfs and kernel EFI binary
installkernel -a /lib/modules

Set kernel command line in /etc/default/uefi-mkconfig:

KERNEL_CONFIG="%entry_id %linux_name Linux %kernel_version ; rd.luks.label=GentooLuks root=LABEL=GentooRoot rootfstype=btrfs rootflags=subvol=@ video=efifb:mode=0"

Now create a boot entry:

uefi-mkconfig
reboot

If EFI stub fails, fall back to GRUB or rEFInd (see Gentoo wiki).

9. System Configuration

Inside the new system (after reboot), complete basic setup:

# Hostname
echo "gentoo" > /etc/hostname

# Clock (if dual‑boot with Windows)
echo 'clock="local"' >> /etc/conf.d/hwclock
echo 'clock_systohc="YES"' >> /etc/conf.d/hwclock

# OpenRC parallel startup
echo 'rc_parallel="YES"' >> /etc/rc.conf
echo 'rc_autostart_user="NO"' >> /etc/rc.conf

# NetworkManager
emerge --ask net-misc/networkmanager
rc-update add NetworkManager default

# User account
useradd -m -s /bin/bash -G audio,video,wheel username
passwd username
EDITOR=nano visudo   # uncomment %wheel ALL=(ALL) ALL

10. Secure Boot (Custom Keys)

We'll generate our own keys and sign the kernel EFI binary.

Install tools:

emerge --ask app-crypt/efitools app-crypt/sbsigntools dev-libs/openssl

Key generation (run as root)

mkdir -p /etc/efikeys && cd /etc/efikeys

# Save current keys (optional, but good for backup)
efi-readvar -v PK -o old_PK.esl
efi-readvar -v KEK -o old_KEK.esl
efi-readvar -v db -o old_db.esl
efi-readvar -v dbx -o old_dbx.esl

# Create GUID
uuidgen --random > guid.txt

# Generate keys (Platform Key, KEK, db)
openssl req -new -x509 -newkey rsa:4096 -subj "/CN=My Platform Key/" -keyout pk.key -out pk.crt -days 3650 -nodes -sha512
openssl req -new -x509 -newkey rsa:4096 -subj "/CN=My Key Exchange Key/" -keyout kek.key -out kek.crt -days 3650 -nodes -sha512
openssl req -new -x509 -newkey rsa:4096 -subj "/CN=My Signature DB Key/" -keyout db.key -out db.crt -days 3650 -nodes -sha512

# Create signature lists
cert-to-efi-sig-list -g "$(< guid.txt)" pk.crt pk.esl
sign-efi-sig-list -k pk.key -c pk.crt PK pk.esl pk.auth

cert-to-efi-sig-list -g "$(< guid.txt)" kek.crt kek.esl
cert-to-efi-sig-list -g "$(< guid.txt)" db.crt db.esl

Enroll keys (UEFI must be in Setup Mode)

# Combine with old keys if you want to keep them
cat old_KEK.esl kek.esl > combined_KEK.esl
cat old_db.esl db.esl > combined_db.esl

# Update variables
efi-updatevar -e -f old_dbx.esl dbx
efi-updatevar -e -f combined_db.esl db
efi-updatevar -e -f combined_KEK.esl KEK
efi-updatevar -f pk.auth PK

Now enable Secure Boot in your UEFI firmware.

Sign the kernel

# Remove old unsigned binaries
rm /efi/EFI/Gentoo/*

# Sign the kernel module (vmlinuz)
sbsign --key /etc/efikeys/db.key --cert /etc/efikeys/db.crt \
  --output "/lib/modules/$(uname -r)/vmlinuz" \
  "/lib/modules/$(uname -r)/vmlinuz"

# Regenerate EFI stub
installkernel

# Verify
sbverify --cert /etc/efikeys/db.crt /efi/EFI/Gentoo/vmlinuz-$(uname -r).efi

11. TPM2 Auto‑Unlock with Clevis

This binds your LUKS key to TPM2 + Secure Boot PCRs, so the system unlocks automatically if firmware/bootloader are unchanged.

Install Clevis

eselect repository enable guru
emerge --sync
ACCEPT_KEYWORDS="~amd64" emerge -a app-crypt/clevis

Bind LUKS slot to TPM2

clevis luks bind -d /dev/nvme0n1p2 tpm2 '{"pcr_bank":"sha256","pcr_ids":"0,7,9"}'
PCR 0 = firmware, PCR 7 = Secure Boot state, PCR 9 = firmware config. Adjust as needed.
clevis encrypt tpm2 '{"pcr_bank":"sha256","pcr_ids":"0"}' < /etc/efikeys/db.key > /etc/efikeys/db.key.jwe

Automate kernel signing during updates

Create a portage hook:

mkdir -p /etc/portage/env/sys-kernel
nano /etc/portage/env/sys-kernel/gentoo-kernel-bin

Content:

pre_pkg_postinst() {
  sbsign --key <(clevis decrypt < /etc/efikeys/db.key.jwe) \
         --cert /etc/efikeys/db.crt \
         --output "/lib/modules/$(uname -r)/vmlinuz" \
         "/lib/modules/$(uname -r)/vmlinuz"
}

Make executable: chmod +x /etc/portage/env/sys-kernel/gentoo-kernel-bin

Now every kernel rebuild will be automatically signed using the TPM‑decrypted key

emerge -1 gentoo-kernel-bin

Finally, regenerate initramfs so the TPM unlock works at boot:

installkernel

12. Troubleshooting & References

  • EFI stub doesn’t appear – Check that /efi/EFI/Gentoo contains .efi files and your firmware boot order includes them.
  • Secure Boot fails – Put your firmware in Setup Mode before enrolling keys. Some boards require clearing Secure Boot settings.
  • TPM unlock not working – Verify TPM is detected: dmesg | grep -i tpm. Also ensure clevis is in your initramfs (dracut should include it automatically).
  • General Gentoo help – Stick to the Gentoo Handbook.
  • Clevis & TPM – Gentoo Wiki: TPM/LUKS

🎉 Final words

You now have a hardened, encrypted, Btrfs‑snapshot‑ready Gentoo system with Secure Boot and TPM2 auto‑unlock. This setup balances security and convenience – the only password you need is your user account’s (and maybe the LUKS fallback password if TPM fails).

Disclaimer: This guide is for advanced users. Always test in a VM first if you’re unsure. The author is not responsible for data loss or bricked firmware.

Enjoy your custom Gentoo build!
Found this helpful? Share the post or leave a comment below.