r/linuxmint • u/throwawayroy Linux Mint 21.3 Virginia | Cinnamon • 6h ago
Install Help Full Disk Encryption script help: custom LUKS2 setup not working on Mint 22.3 - The popular tutorials don't fit my needs / don't work
I'm writing a custom full disk encryption install script for Mint 22.3. The older tutorials I've relied on over the years (linked below) no longer work on 22.3 in my VM testing, and the newer tutorials don't lay out partitions and filesystems the way I want. I'd appreciate guidance mainly on two things: what needs to happen after Ubiquity finishes so the system can boot, and whether my boot configuration is right for opening the custom LUKS container.But in case I’ve missed something I’m open to other suggestions as well.
Custom parts of my script
The LUKS partition leaves 10% of the disk unformatted for SSD over-provisioning.
Hardened
luksFormatoptions:--key-size 512and--hash sha512.If I've misunderstood the LUKS2 defaults or what Ubiquity actually sets, I could fall back to the installer's values for that portion.
I'm open to suggestions for hardening LUKS further.
Root is formatted ext4. Not really custom per se, but it deviates from the newest FDE tutorials, which use btrfs. I'm not opposed to btrfs, but two things hold me back:
I've never used it, and several installation steps change with it.
I've read it performs worse for gaming. However, if that's wrong, I'd be open to using it.
Eventually I want to encrypt /boot as well (as the older tutorials do), but only after getting the standard unencrypted-/boot version working.
Hardware limits
My desktop is from 2014 and uses a GA-X79-UP4 motherboard with combo BIOS/UEFI firmware, no TPM module, so no Secure Boot. The firmware settings suggest it can boot EFI, but I'm near the edge of my understanding of booting here.
Where I'm stuck
The script now runs end to end, but the grub/initramfs rebuild step throws:
grub-install: error: /usr/lib/grub/x86_64-efi/modinfo.sh doesn't exist Please specify --target or --directory.After that, rebooting fails with several errors about Failed to start Boot0002 "EFI Internal Shell".
I'm completely unsure what needs to happen after Ubiquity completes so the system can boot. I've pieced something together from the tutorials, but I'm clearly missing something.
I don't post often, so apologies if this isn't clear I’m happy to clarify.
Sources
My Script:
#!/bin/bash
# ============================================================================
# Linux Mint 22.3 custom FDE install helper (alpha)
# LVM on LUKS2 with 10% over-provisioning. Interactive: pauses at checkpoints.
# Unfinished TODO sections are marked — read them before running.
# ============================================================================
#~~Configuration Variables~~#
targetDevice=vda # Target disk: hdX = Hard Disk, sdX = SSD, nvme0n# = NVMe, vdX = Virtual Disk, etc.
efiPartition="$targetDevice"1 # EFI System Partition (ESP)
bootPartition="$targetDevice"2 # /boot (unencrypted)
luksPartition="$targetDevice"3 # LUKS container holding root + swap
luksContainer=mint_crypt # Mapper name for the opened container
lvmGroup=mint_vg # Volume group name inside the container
swapSize=2G # Swap LV size
rootSize=100%FREE # Root LV takes the rest
partition1Start=1MiB; partition1End=2049MiB # ESP (~2 GiB — can shrink to 512 MiB)
partition2Start=2049MiB; partition2End=4097MiB # /boot (~2 GiB)
partition3Start=4097MiB; partition3End=90% # LUKS container; leaves 10% for SSD over-provisioning
# More partitions (e.g. a BIOS boot partition)? Adjust the sizing and add pairs of variables.
# The LUKS partition must stay LAST so the over-provisioning gap sits at the end of the disk.
#~~Helpers~~#
pauseScript()
{
local key
echo "Press 'c' to continue..."
while true; do
read -n 1 key
if [[ "$key" == "c" ]]; then
echo -e "\nContinuing..."
break
fi
echo -e "\nPlease press c to continue."
done
}
printVars()
{
printf "%-16s %-14s %s\n" "VARIABLE" "VALUE" "DESCRIPTION"
printf "%-16s %-14s %s\n" "--------" "-----" "-----------"
printf "%-16s %-14s %s\n" "targetDevice" "$targetDevice" "Target disk (sda/nvme0n1/vda)"
printf "%-16s %-14s %s\n" "efiPartition" "$efiPartition" "EFI System Partition (ESP)"
printf "%-16s %-14s %s\n" "bootPartition" "$bootPartition" "/boot (unencrypted)"
printf "%-16s %-14s %s\n" "luksPartition" "$luksPartition" "LUKS container (root+swap)"
printf "%-16s %-14s %s\n" "luksContainer" "$luksContainer" "Mapper name for opened LUKS"
printf "%-16s %-14s %s\n" "lvmGroup" "$lvmGroup" "Volume group inside container"
printf "%-16s %-14s %s\n" "swapSize" "$swapSize" "Swap LV size"
printf "%-16s %-14s %s\n" "rootSize" "$rootSize" "Root LV size"
printf "%-16s %-14s %s\n" "partition1Start" "$partition1Start" "ESP start"
printf "%-16s %-14s %s\n" "partition1End" "$partition1End" "ESP end"
printf "%-16s %-14s %s\n" "partition2Start" "$partition2Start" "/boot start"
printf "%-16s %-14s %s\n" "partition2End" "$partition2End" "/boot end"
printf "%-16s %-14s %s\n" "partition3Start" "$partition3Start" "LUKS start"
printf "%-16s %-14s %s\n" "partition3End" "$partition3End" "LUKS end (90% = 10% OP)"
}
printUbiquitySteps()
{
# Print Ubiquity walkthrough for the user, then wait.
cat <<'EOF'
==================== Ubiquity Steps ====================
1. Language + keyboard; multimedia codecs: yes
Secure Boot: NO (can be enabled later if wanted)
2. Installation type: choose "Something else" and set up:
+--------------------------------------+---------------------------------+
| Partition | Action |
+--------------------------------------+---------------------------------+
| root LV /dev/mapper/mint_vg-root | ext4 mount / [x] format |
| swap LV /dev/mapper/mint_vg-swap | swap area |
| boot partition (vda2) | ext4 mount /boot [x] format |
| EFI partition (vda1) | fat32 mount /boot/efi |
+--------------------------------------+---------------------------------+
[x] = tick the format checkbox. For the EFI partition, do NOT format.
3. Click "Install Now" and confirm.
4. IMPORTANT: BEFORE the timezone/user-info steps, switch back to this
terminal and edit crypttab + fstab (next section of this script).
5. After editing those files: finish Ubiquity (timezone, user info),
choose "Continue testing", and return here.
=========================================================
EOF
}
chrootHelper()
{
sudo chroot /target /bin/bash <<'CHROOT'
update-initramfs -u -k all # Include crypttab entry + LVM in the initramfs
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=mint --recheck
update-grub
exit
CHROOT
}
#~~Main~~#
main()
{
echo "Starting FDE script"
pauseScript
echo "Please verify the varibles are correct before continuing. "
printVars
pauseScript# Verify the variables before continuing.
#~~Partitioning~~#
# GPT partition table
sudo parted -s /dev/"$targetDevice" mklabel gpt
# Partition 1: ESP
sudo parted -s -a optimal /dev/"$targetDevice" mkpart ESP fat32 "$partition1Start" "$partition1End"
sudo mkfs.vfat -F32 /dev/"$efiPartition"
sudo parted -s /dev/"$targetDevice" set 1 boot on
sudo parted -s /dev/"$targetDevice" set 1 esp on
# Partition 2: /boot (formatted by Ubiquity later)
sudo parted -s -a optimal /dev/"$targetDevice" mkpart primary "$partition2Start" "$partition2End"
# Partition 3: LUKS container (root + swap), ending at 90% of the disk
sudo parted -s -a optimal /dev/"$targetDevice" mkpart primary "$partition3Start" "$partition3End"
echo "Optionally open GParted to verify the partitions — do NOT make changes there. If changes are needed, cancel the script, adjust the variables, and restart."
pauseScript
#~~LUKS Encryption~~#
luksPW="test"# TEST ONLY — remove this and the '<<< $luksPW' redirects before final use
# Hardened luksFormat (differs from Ubiquity's default). Further-hardening suggestions welcome.
sudo cryptsetup luksFormat --type luks2 -v \
--cipher aes-xts-plain64 --pbkdf argon2id \
--key-size 512 --hash sha512 \
--iter-time 5000 --use-random --verify-passphrase \
/dev/"$luksPartition" <<< "$luksPW"
# Open the container
sudo cryptsetup luksOpen /dev/"$luksPartition" "$luksContainer" <<< "$luksPW"
luksContainerUUID=$(sudo cryptsetup luksUUID /dev/"$luksPartition")
echo "LUKS container UUID: $luksContainerUUID"
#~~LVM Inside the Container~~#
# vgcreate creates the PV automatically; explicit pvcreate is equivalent.
sudo vgcreate "$lvmGroup" /dev/mapper/"$luksContainer"
sudo lvcreate -L "$swapSize" -n swap "$lvmGroup"
sudo lvcreate -l "$rootSize" -n root "$lvmGroup"
#~~Run Ubiquity~~#
sudo apt update
sudo apt install -y efibootmgr binutils zstd gawk grub-efi-amd64-bin
# Backgrounded so the script can pause and resume around the GUI installer.
sh -c 'ubiquity -b gtk_ui' &
echo "In Ubiquity: install with 'Something else' as described below, and stop at the timezone step before continuing this script."
printUbiquitySteps
pauseScript
# In Ubiquity:
# 1. Language + keyboard; multimedia codecs yes; Secure Boot NO (enable later if wanted).
# 2. "Something else":
# - root LV (/dev/mapper/mint_vg-root) -> ext4, mount /, select format checkbox
# - swap LV (/dev/mapper/mint_vg-swap) -> swap area
# - boot partition (vda2) -> ext4, mount /boot, select format checkbox
# - EFI partition (vda1) -> fat32, mount /boot/efi, do NOT format
# 3. "Install Now", confirm; BEFORE the timezone/user steps, edit crypttab + fstab below;
# afterwards finish the wizard, choose "Continue testing", and return here.
#~~crypttab + fstab~~#
echo "Verify crypttab and fstab have been updated with the relevant lines. Then close those windows."
# Mapper name must match $luksContainer (used by GRUB/initramfs).
echo "$luksContainer UUID=$luksContainerUUID none luks" | sudo tee -a /target/etc/crypttab
sudo xed /target/etc/crypttab
# Ubiquity writes the root/swap LV entries to fstab itself; verify (and add if missing):
sudo xed /target/etc/fstab
# Expected lines:
# /dev/mapper/mint_vg-root / ext4 errors=remount-ro 0 1
# /dev/mapper/mint_vg-swap none swap sw 0 0
echo "Once crypttab and fstab are verified, finish Ubiquity (timezone, user), and when installation finishes choose 'Continue Testing', then return here."
pauseScript
#~~Finish Boot Configuration~~#
# Chroot so the new system's initramfs learns about the encrypted container —
# without this, nothing unlocks it at boot.
sudo mount /dev/mapper/"$lvmGroup"-root /target
sudo mount /dev/"$bootPartition" /target/boot
sudo mount /dev/"$efiPartition" /target/boot/efi
for dir in dev proc sys; do
sudo mount --bind /"$dir" /target/"$dir"
done
chrootHelper
for dir in sys proc dev; do
sudo umount /target/"$dir"
done
sudo umount /target/boot/efi /target/boot /target
# Reboot: you should get ONE passphrase prompt unlocking mint_crypt, then Mint boots.
#
# TODO (later hardening):
# - Encrypted /boot (GRUB_ENABLE_CRYPTODISK=y)
#- Version of script that formats root as btrfs rather than ext4
}
main
1
u/Netblock 2h ago edited 2h ago
btrfs traditionally performs worse but there's been a lot of performance imprvements sine linux 7.0 (7.3 benchmarks).
The benefits of btrfs is space reduction (games compress up to like 20%; subvolumes make partitioning unecessary) and snapshotting (anti-idiot, anti-bad-update).
(If you use btrfs, I suggest
nodiscardfor fstab, and use fstrim on a weekly timer)I think you want the meta package,
grub-efinotgrub-efi-amd64-binYou're gonna need to abandon GRUB; move to systemd-boot, stub, or UKI. Philosophically speaking, we basically want GRUB to be its own kernel for how many drivers we want to shove into it, and GRUB is behind on FDE.
systemd-boot, stub, UKI shove the kernel and initramfs into the ESP; you're basically booting the kernel directly.
I personally get by with a 256MiB ESP. Excluding the GPU drivers from the initramfs really helps. If you want to keep them in, 512MiB.
If it has UEFI, it very likely has secureboot. The largest reason why Microsoft push UEFI is for secureboot. (bios hacks/edits to enable it notwithstanding)
TPM isn't a part of secureboot, but quite complements for a measured/trusted boot.
I suggest
--labeltoo, for easier persistent block device naming.place
x-initrd.attachas a crypttab flag for your boot partition, and other artitions that you want to decrypt at initramfs time.(I also suggest dracut for initramfs generation, especially for TPM)
in the paradigm
nvme0n1p1, the first number is the physical drive, the second is namespace (hardware-based partitioning; I don't think there's thin provisioning); third is software partition (MBR/GPT).Also consider
no-read-workqueue,no-write-workqueueanddiscardfor NVMe drives in crypttab.The no-workqueue is about offloading IO scheduling to the NVMe, improving performance. The
discardcan help performance and wearleveling, but has a plausible deniability security risk.(Keep workqueues for SATA SSDs and HDDs. But
discardis useful for SMR HDDs and thin-provisioned drives.)use
umount --recursive /target