Why This Architecture?
Traditional backup systems are reactive—they help after things go wrong. Modern Linux distributions like Kali Linux "Unkaputtbar" and Fedora Silverblue take a proactive approach: every system change creates a snapshot automatically, and you can boot from any snapshot at any time.
This guide implements the Kali Linux "Unkaputtbar" (unbreakable) architecture:
- Snapper (not Timeshift) for automatic pre/post-APT snapshots on every install/remove/upgrade
- Writable bootable snapshots you can actually work in (not just read-only recovery)
- Kali-style subvolume layout that separates system areas for clean rollbacks
- grub-btrfs integration for boot menu snapshot selection
By the end of this guide, you'll have:
- LUKS2 encrypted root filesystem with separate unencrypted ESP
- Kali-style BTRFS subvolume layout (@, @home, @root, @srv, @tmp, @usr/local, @var/log, @.snapshots)
- Snapper automatic snapshots before/after every APT operation
- Writable bootable snapshots via grub-btrfs integration
- Test-and-rollback workflow boot snapshots read-write before promoting to main
- Wayland-first GNOME with modern session management
Architecture Overview (Kali "Unkaputtbar" Style)
Our target architecture follows Kali Linux's "Unkaputtbar" (unkaputtbar = unbreakable) design, which uses Snapper for APT-integrated snapshots:
Disk Layout (Kali Linux "Unkaputtbar" Style):
├── /dev/nvme0n1p1 [ESP] 512MB FAT32 /boot/efi
├── /dev/nvme0n1p2 [CRYPT] Rest LUKS2 Encrypted container
│ └── /dev/mapper/crypt_root
│ └── btrfs filesystem
│ ├── @ [ROOT] / (main system)
│ ├── @home [HOME] /home (user data)
│ ├── @root [ROOT_HOME] /root (root home)
│ ├── @srv [SRV] /srv (site data)
│ ├── @tmp [TMP] /tmp (temp files)
│ ├── @usr_local [LOCAL] /usr/local (local admin)
│ ├── @var_log [LOGS] /var/log (system logs)
│ └── @.snapshots [SNAPSHOTS] /.snapshots (snapper dir)
Automatic Protection:
├─ Pre-apt: Snapshot created before every "apt install/remove/upgrade"
├─ Post-apt: Snapshot created after APT operation completes
└─ Boot: grub-btrfs menu lists all snapshots for boot selection
This separation provides several advantages:
- OS snapshots don't include user data or logs, keeping backups small
- Automatic APT protection via Snapper hooks (every install/remove/upgrade)
- Writable bootable snapshots let you test fixes before committing
- Clean rollback by isolating logs, cache, and temp files from system state
- Desktop manager support with dedicated subvolumes for GDM/lightdm
Why Snapper (Not Timeshift)?
| Feature | Snapper (Recommended) | Timeshift |
|---|---|---|
| Automatic APT Hooks | ✅ Native pre/post hooks | ❌ Manual/API only |
| Multiple Configurations | ✅ Separate configs for /, /home, custom paths | ❌ Single config |
| Diff Support | ✅ Full file-by-file diff | ⚠️ Limited |
| GUI Available | ✅ snapper-gui | ✅ Built-in |
| Enterprise Origin | ✅ SUSE/Obsidian (enterprise-tested) | Community |
| Desktop Fixes Required | Separate @var_lib_gdm3 subvolume needed | Minimal |
apt install/remove/upgrade automatically creates snapshots—transparent protection against broken upgrades. Kali Linux "Unkaputtbar" uses Snapper for this exact reason.
Phase 1: Partitioning with gdisk
UEFI systems require GPT partitioning. We'll use gdisk directly rather than parted for precise control. We're creating:
- Partition 1: EFI System Partition (ESP) — 1GB, FAT32, unencrypted
- Partition 2: Linux filesystem — LUKS2 encrypted, BTRFS
/dev/nvme0n1 (or your target disk) is correct. Substitute your actual device name throughout this guide.
1.1 Identify Target Disk
# List block devices with human-readable sizes
lsblk -dpno NAME,SIZE,MODEL,TRAN | grep -E 'nvme|sd|vd'
Look for entries like /dev/nvme0n1 or /dev/sda. Note the device path—you'll use it for all partitioning operations.
1.2 Create GPT Partition Table
# Install gdisk if not already present (most live environments include it)
sudo apt update && sudo apt install -y gdisk
# Launch gdisk on target disk
sudo gdisk /dev/nvme0n1
At gdisk prompts, execute these commands:
Command (? for help): o # Create new GPT
Proceed? (Y/N): y # Confirm
Command (? for help): n # New partition
Partition number (1-128, default 1): 1
First sector (34-...): [Enter] # Default
Last sector: +1G # 1GB ESP
Hex code or GUID: ef00 # EFI System
Command (? for help): n # New partition
Partition number (2-128, default 2): 2
First sector: [Enter] # Default
Last sector: [Enter] # Remainder
Hex code or GUID: 8304 # Linux x86-64 root (/) or 8300 for Linux filesystem
Command (? for help): w # Write changes
Do you want to proceed? (Y/N): y # Confirm
Verify the partition structure:
sudo gdisk -l /dev/nvme0n1
Expected output:
Number Start (sector) End (sector) Size Code Name
1 2048 2099199 1024.0 MiB EF00 EFI System
2 2099200 [end] [size] 8304 Linux root x86-64
1.3 Format ESP
# Create FAT32 filesystem with proper ESP alignment
sudo mkfs.vfat -F 32 -n ESP /dev/nvme0n1p1
# Verify
sudo fatlabel /dev/nvme0n1p1
Phase 2: LUKS2 Encryption Setup
LUKS2 (Linux Unified Key Setup version 2) provides full-disk encryption with PBKDF2 or Argon2 key derivation, multiple key slots, and authenticated encryption options. Unlike LUKS1, LUKS2 supports online re-encryption and improved header resilience.
2.1 Create LUKS2 Container
# Install cryptsetup (usually present on live ISOs)
sudo apt install -y cryptsetup-bin
# Create LUKS2 container with Argon2id (memory-hard KDF, resistant to GPU cracking)
sudo cryptsetup luksFormat \
--type luks2 \
--cipher aes-xts-plain64 \
--key-size 512 \
--hash sha256 \
--pbkdf argon2id \
--pbkdf-memory 1048576 \
--iter-time 2000 \
/dev/nvme0n1p2
--cipher aes-xts-plain64: Industry-standard cipher with sector-level encryption--key-size 512: XTS mode uses two keys; 256 bits each, totaling 512--pbkdf argon2id: Memory-hard KDF; resistance to ASIC/GPU attacks--pbkdf-memory 1048576: 1GB memory cost for Argon2--iter-time 2000: 2-second unlock target (balances security/usability)
You'll be prompted for a passphrase. Use a strong, memorable passphrase—this is your primary decryption key. Consider using a passphrase manager or Diceware methodology.
2.2 Open the Encrypted Device
# Open the LUKS container, mapping to /dev/mapper/crypt_root
sudo cryptsetup open /dev/nvme0n1p2 crypt_root
# Verify it's mapped
ls -la /dev/mapper/crypt_root
sudo cryptsetup status crypt_root
The crypt_root name is arbitrary—it's used for the device mapper path. You could use any identifier, but crypt_root is conventional and clear.
2.3 Backup LUKS Header (Critical Step)
# Create backup directory
mkdir -p ~/luks-backups
# Backup header to external storage (USB, network, etc.)
sudo cryptsetup luksHeaderBackup /dev/nvme0n1p2 \
--backup-file ~/luks-backups/luks-header-$(date +%Y%m%d).backup
# Also backup to external USB if available
# sudo cp ~/luks-backups/luks-header-*.backup /media/usb/
Phase 3: BTRFS Setup and Subvolume Layout
BTRFS (B-tree filesystem) provides COW (Copy-on-Write), checksums, compression, and subvolumes. Unlike LVM snapshots, BTRFS snapshots are instantaneous and space-efficient—only changed blocks consume additional space.
3.1 Create BTRFS Filesystem
# Install btrfs-progs
sudo apt install -y btrfs-progs
# Create filesystem with Fedora-inspired options
sudo mkfs.btrfs \
--label debian_root \
--features extref,skinny-metadata,quota \
/dev/mapper/crypt_root
# Verify features
sudo btrfs filesystem show /dev/mapper/crypt_root
extref for extended references, skinny-metadata for reduced metadata overhead, and quota for snapshot tracking—same features Fedora enables by default since Fedora 33.
Parameter explanations:
--label: Human-readable filesystem labelextref: Extended inode references (Fedora default)skinny-metadata: Reduced metadata sizequota: Quota support for snapshot accounting
3.2 Create Mount Point and Mount
# Create temporary mount point for initial setup
sudo mkdir -p /mnt/debian
# Mount the BTRFS root (this is the filesystem root, not the @ subvolume)
sudo mount /dev/mapper/crypt_root /mnt/debian
# Verify
sudo btrfs filesystem show /mnt/debian
3.3 Create Subvolumes (Kali "Unkaputtbar" Layout)
This is the Kali Linux "Unkaputtbar" subvolume layout—same as used by Kali's snapshot methodology:
# Create subvolumes (Kali Linux "Unkaputtbar" layout)
cd /mnt/debian
# Core system subvolumes
sudo btrfs subvolume create @ # Root filesystem
sudo btrfs subvolume create @home # User home directories
sudo btrfs subvolume create @root # Root user's home
sudo btrfs subvolume create @srv # Site-specific data
sudo btrfs subvolume create @tmp # Temporary files
sudo btrfs subvolume create @usr_local # Local admin packages
sudo btrfs subvolume create @var_log # System logs
# Snapshots directory (Snapper expects @.snapshots, not @snapshots)
# IMPORTANT: If using snapper create-config later, it will create this automatically
# If you create it manually here, use: snapper -c root create-config / --fstype btrfs
# Or alternatively, skip this step and let snapper create it
sudo btrfs subvolume create @.snapshots
# Desktop manager subvolume (required for Snapper read-only boots)
sudo btrfs subvolume create @var_lib_gdm3
# Verify (should show all subvolumes)
sudo btrfs subvolume list .
# IMPORTANT: Migrate existing data before mounting subvolumes
# If GDM/AccountsService files exist in the chroot, they must be moved to subvolumes
# This happens AFTER debootstrap (Phase 4) but BEFORE first boot
# See Phase 7.3 for GDM/AccountsService data migration during system configuration
Expected output:
ID 256 gen 5 top level 5 path @
ID 257 gen 6 top level 5 path @home
ID 258 gen 7 top level 5 path @root
ID 259 gen 8 top level 5 path @srv
ID 260 gen 9 top level 5 path @tmp
ID 261 gen 10 top level 5 path @usr_local
ID 262 gen 11 top level 5 path @var_log
ID 263 gen 12 top level 5 path @.snapshots
ID 264 gen 13 top level 5 path @var_lib_gdm3
@.snapshots (with a dot), not @snapshots. This is the convention used by openSUSE and Kali Linux.
3.4 Mount Subvolumes (Kali Layout)
Unmount the raw filesystem and mount Kali-style subvolumes:
# Unmount root, then mount subvolumes properly
sudo umount /mnt/debian
# Mount root with Fedora-recommended options (zstd:1)
# Add autodefrag for automatic defragmentation on all writes
sudo mount -o subvol=@,compress=zstd:1,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian
# Remount to apply autodefrag (kernel may need explicit remount)
sudo mount -o remount,autodefrag /mnt/debian
# Create mount points
sudo mkdir -p /mnt/debian/{boot/efi,home,root,srv,tmp,usr/local,var/log,.snapshots}
sudo mkdir -p /mnt/debian/var/lib/gdm3
# Mount Kali-style subvolumes
sudo mount -o subvol=@home,compress=zstd:1,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian/home
sudo mount -o subvol=@root,compress=zstd:1,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian/root
sudo mount -o subvol=@srv,compress=zstd:1,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian/srv
sudo mount -o subvol=@tmp,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian/tmp
sudo mount -o subvol=@usr_local,compress=zstd:1,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian/usr/local
sudo mount -o subvol=@var_log,compress=zstd:1,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian/var/log
sudo mount -o subvol=@.snapshots,compress=zstd:1,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian/.snapshots
# Desktop manager subvolume (required for snapper read-only boots)
sudo mount -o subvol=@var_lib_gdm3,compress=zstd:1,noatime,autodefrag \
/dev/mapper/crypt_root /mnt/debian/var/lib/gdm3
# Mount ESP
sudo mount /dev/nvme0n1p1 /mnt/debian/boot/efi
zstd:1 compression—level 3+ gives diminishing returns for significantly higher CPU usage. zstd:1 achieves ~15-30% space savings with minimal performance impact, matching modern enterprise Linux defaults.
Mount option explanations:
subvol=@: Mounts the subvolume instead of the filesystem rootcompress=zstd:1: Transparent Zstd compression (level 1 is Fedora default - best speed/compression ratio)noatime: Don't update access times (reduces COW churn)autodefrag: Automatically defragments files—prevents long-term fragmentation on COW filesystems when combined with compression or snapper snapshots (enterprise recommended)space_cache=v2: Improved free space caching
autodefrag automatically defragments files when they exceed 90% fragmentation, running in the background with minimal impact. This is explicitly recommended by SUSE/openSUSE for production BTRFS deployments.
3.5 Verify Mount Structure
# Display mount hierarchy
findmnt /mnt/debian
# Or use df for disk usage
df -hT /mnt/debian /mnt/debian/*
Phase 4: debootstrap Base System
debootstrap creates a minimal Debian system in a target directory. Unlike the graphical installer, it gives complete control over package selection and configuration.
4.1 Install debootstrap
# Install debootstrap and essential tools
sudo apt install -y debootstrap binutils gdisk arch-install-scripts
4.2 Run debootstrap
Debian 13 is currently trixie (testing). For the latest stable, substitute stable or the release codename:
# Install base system (using trixie for Debian 13)
sudo debootstrap \
--variant=minbase \
--include=linux-image-amd64,locales,initramfs-tools,cryptsetup,btrfs-progs,sudo,vim,nano,curl,wget \
trixie \
/mnt/debian \
http://deb.debian.org/debian/ 2>&1 | tee ~/debootstrap.log
This downloads and installs the base system. Output is tee'd to a log file for troubleshooting.
4.3 Bind Mount System Directories
The chroot needs access to runtime information from the host:
# Bind mount essential filesystems
sudo mount --bind /dev /mnt/debian/dev
sudo mount --bind /dev/pts /mnt/debian/dev/pts
sudo mount --bind /proc /mnt/debian/proc
sudo mount --bind /sys /mnt/debian/sys
sudo mount --bind /run /mnt/debian/run
# For networking inside chroot
sudo cp /etc/resolv.conf /mnt/debian/etc/resolv.conf
4.4 Enter Chroot Environment
# Enter chroot with full environment
sudo chroot /mnt/debian /bin/bash
# Welcome to your new Debian system!
ls /
whoami # Should show 'root'
Phase 5: System Configuration Inside Chroot
Now we configure the base system: networking, authentication, crypto integration, and package management.
5.1 Configure Filesystem Table (fstab) - Kali Layout
Use UUIDs for device identification. This fstab includes the Kali "Unkaputtbar" subvolume layout:
# Get UUIDs
blkid /dev/nvme0n1p1 # ESP UUID
blkid /dev/nvme0n1p2 # LUKS UUID
# Get the root filesystem UUID (inside LUKS)
blkid /dev/mapper/crypt_root
# Create fstab for Kali-style subvolume layout
cat > /etc/fstab << 'EOF'
# /etc/fstab - Kali Linux "Unkaputtbar" subvolume layout
#
# Encrypted BTRFS root (Fedora uses zstd:1)
UUID=PLACEHOLDER_CRYPT_ROOT / btrfs subvol=@,compress=zstd:1,noatime,autodefrag 0 0
# Core subvolumes
UUID=PLACEHOLDER_CRYPT_ROOT /home btrfs subvol=@home,compress=zstd:1,noatime,autodefrag 0 0
UUID=PLACEHOLDER_CRYPT_ROOT /root btrfs subvol=@root,compress=zstd:1,noatime,autodefrag 0 0
UUID=PLACEHOLDER_CRYPT_ROOT /srv btrfs subvol=@srv,compress=zstd:1,noatime,autodefrag 0 0
# Temp storage (tmpfs preferred over btrfs for /tmp performance)
# Note: @tmp subvolume was created but tmpfs provides better performance for temp files
# tmpfs is volatile (cleared on reboot); uncomment below if you prefer persistent /tmp:
# UUID=PLACEHOLDER_CRYPT_ROOT /tmp btrfs subvol=@tmp,noatime,autodefrag 0 0
UUID=PLACEHOLDER_CRYPT_ROOT /usr/local btrfs subvol=@usr_local,compress=zstd:1,noatime,autodefrag 0 0
UUID=PLACEHOLDER_CRYPT_ROOT /var/log btrfs subvol=@var_log,compress=zstd:1,noatime,autodefrag 0 0
UUID=PLACEHOLDER_CRYPT_ROOT /.snapshots btrfs subvol=@.snapshots,compress=zstd:1,noatime,autodefrag 0 0
# Desktop manager subvolume (required for Snapper read-only boots)
UUID=PLACEHOLDER_CRYPT_ROOT /var/lib/gdm3 btrfs subvol=@var_lib_gdm3,compress=zstd:1,noatime,autodefrag 0 0
# EFI System Partition
UUID=PLACEHOLDER_ESP /boot/efi vfat umask=0077,codepage=437,iocharset=ascii 0 1
# Tmpfs for performance
tmpfs /tmp tmpfs defaults,nosuid,nodev,size=50% 0 0
EOF
# Now substitute UUIDs
crypt_uuid=$(blkid -s UUID -o value /dev/mapper/crypt_root)
esp_uuid=$(blkid -s UUID -o value /dev/nvme0n1p1)
sed -i "s/PLACEHOLDER_CRYPT_ROOT/$crypt_uuid/g" /etc/fstab
sed -i "s/PLACEHOLDER_ESP/$esp_uuid/g" /etc/fstab
# Verify
cat /etc/fstab
5.2 Configure crypttab for Auto-Unlock
# Create crypttab with the same mapper name
echo "crypt_root UUID=$crypt_uuid none luks,discard" > /etc/crypttab
# Verify
cat /etc/crypttab
Note: discard enables TRIM on SSDs, which can weaken security against sophisticated attacks but is required for SSD longevity. Remove if using a security-focused threat model.
5.3 Enable systemd-cryptsetup (Modern Alternative)
Modern Fedora systems use systemd-cryptsetup, which integrates encryption with systemd's native device management. Debian Trixie (13) supports this via systemd-cryptsetup.
# Install systemd-cryptsetup
apt install -y systemd-cryptsetup
# Modern approach: systemd-cryptsetup uses crypttab automatically
# But for TPM integration (Phase 11), systemd-cryptenroll is preferred
# Verify systemd-cryptsetup is active
systemctl status systemd-cryptsetup@
# systemd-cryptsetup advantages:
# - Parallelized device unlock (simultaneous prompts for multiple disks)
# - TPM2 integration for auto-unlock without initramfs changes
# - Proper dependency ordering in systemd's boot sequence
# - No cryptsetup binary in initramfs (smaller initramfs)
# Check systemd version support
systemctl --version # Requires v248+ for TPM2 enroll
5.4 Configure Hostname and Hosts
# Set hostname (adjust as desired)
echo "titanium-workstation" > /etc/hostname
# Configure hosts
cat > /etc/hosts << 'EOF'
127.0.0.1 localhost
127.0.1.1 titanium-workstation
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
5.5 Configure Locale and Timezone
# Generate locales
apt install -y locales
sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
locale-gen
# Set default locale
echo 'LANG=en_US.UTF-8' > /etc/default/locale
# Set timezone (adjust to your location)
ln -sf /usr/share/zoneinfo/Europe/London /etc/localtime
dpkg-reconfigure -f noninteractive tzdata
5.6 Configure APT Sources
# Create sources.list
cat > /etc/apt/sources.list << 'EOF'
deb http://deb.debian.org/debian trixie main contrib non-free-firmware
deb http://security.debian.org/debian-security trixie-security main contrib
EOF
# Update package lists
apt update
# Install essential packages
apt install -y \
apt-transport-https \
ca-certificates \
gnupg \
software-properties-common \
bash-completion \
htop \
git \
build-essential \
dkms \
linux-headers-amd64
5.7 Configure Initramfs for Encrypted Boot
The initramfs must unlock the LUKS container before mounting root:
# Ensure cryptsetup is included in initramfs
apt install -y cryptsetup-initramfs
# Update initramfs
cryptsetup-initramfs
# Regenerate initramfs for all kernels
update-initramfs -u -k all
# Verify the generated image contains crypto modules
lsinitramfs /boot/initrd.img-* | grep cryptsetup
5.8 Set Root Password
# Set secure root password
passwd root
Use a strong, unique password. This is for emergency recovery only.
5.9 Create Regular User
# Create user with sudo privileges
useradd -m -s /bin/bash -G sudo,audio,video,cdrom,floppy,adm,users,netdev stefan
passwd stefan
# Configure sudo for no-password (optional, security trade-off)
echo 'stefan ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/stefan
chmod 440 /etc/sudoers.d/stefan
Phase 6: Bootloader and grub-btrfs
Exit the chroot and configure the bootloader from the live environment.
# Exit chroot
exit
# Return to live environment prompt
# Verify you're outside chroot (prompt changes)
6.1 Install GRUB Bootloader
# Install GRUB for UEFI
sudo apt install -y grub-efi-amd64 grub-efi-amd64-signed shim-signed
# Install GRUB to target system
sudo grub-install \
--target=x86_64-efi \
--efi-directory=/mnt/debian/boot/efi \
--bootloader-id=debian \
--root-directory=/mnt/debian \
--removable
--removable flag: Creates /EFI/BOOT/BOOTX64.EFI, the fallback boot path. Useful for removable media and ensures boot even if NVRAM entries are lost.
6.2 Build grub-btrfs from Source
grub-btrfs adds boot menu entries for BTRFS snapshots. This is the feature that makes snapshots truly useful.
Note: grub-btrfs is not in standard Debian repositories—you must build it from source.
# Install dependencies
sudo apt install -y \
git \
make \
gawk \
btrfs-progs \
grub-common
# Clone repository
cd /tmp
git clone https://github.com/Antynea/grub-btrfs.git
cd grub-btrfs
# Checkout latest stable (v4.12 as of 2026)
git checkout v4.12
# Review the Makefile
less Makefile
6.3 Configure and Install grub-btrfs
# Review configuration defaults
cat config
Edit the config before installation. Key settings to verify:
# Create config override for BOOTABLE WRITABLE SNAPSHOTS
cat > /tmp/grub-btrfs/config << 'EOF'
# grub-btrfs configuration - Bootable Writable Snapshots Version
# Enable snapshots in boot menu
GRUB_BTRFS_ENABLE="true"
# Snapshot submenu name
GRUB_BTRFS_SUBMENUNAME="Bootable Snapshots"
# Show snapshot name in menu
GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="true"
# Number of snapshots to show
GRUB_BTRFS_LIMIT="50"
# Subvolume where snapshots are stored
GRUB_BTRFS_SUBVOLUME="/.snapshots"
# Name of the snapshot directory
GRUB_BTRFS_SNAPSHOT_SUBMENU="📸 Snapshot"
# Add version tag to snapshot name
GRUB_BTRFS_SHOW_VERSION="true"
# Date format
GRUB_BTRFS_DATE_FORMAT="%Y-%m-%d %H:%M"
# CRITICAL: Enable WRITABLE snapshots (not read-only)
# This allows you to boot into a snapshot, test changes, and rollback if needed
# Without this, snapshots boot read-only and cannot be modified
# Override default ro with rw for writable boot
GRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS="rw quiet rootflags=subvol=@.snapshots/%s"
# Disable fallback (we'll use initramfs)
GRUB_BTRFS_DISABLE_FALLBACK_SNAPSHOT="true"
# Optional: Show kernel version in menu
GRUB_BTRFS_SHOW_KERNEL_VERSION="true"
EOF
Writable Snapshots Explained: By default, grub-btrfs boots snapshots read-only (-ro flag). The config above overrides this with rw and sets rootflags=subvol=@snapshots/%s which boots directly into the snapshot subvolume. This creates a fully bootable, writable recovery environment where you can test fixes before rollback.
Now install:
# Install to target system
cd /tmp/grub-btrfs
sudo make install DESTDIR=/mnt/debian
# Verify installation
ls -la /mnt/debian/etc/grub.d/ | grep btrfs
6.4 Configure GRUB for LUKS and BTRFS
# Edit GRUB default configuration
sudo nano /mnt/debian/etc/default/grub
Key modifications:
# GRUB config - ensure these settings
GRUB_DEFAULT=0
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR="Debian"
# Critical: enable cryptodisk for LUKS
GRUB_ENABLE_CRYPTODISK=y
# Enable BTRFS support
GRUB_PRELOAD_MODULES="part_gpt part_msdos cryptodisk luks btrfs"
# Kernel command line - UUID and crypt_root
GRUB_CMDLINE_LINUX="cryptdevice=UUID=YOUR_CRYPT_UUID:crypt_root root=/dev/mapper/crypt_root"
# Quiet boot with encryption prompts
GRUB_CMDLINE_LINUX_DEFAULT="quiet boot=live persistent"
# Show menu (not hidden)
GRUB_TIMEOUT_STYLE=menu
# Use GFXterm for better display
GRUB_TERMINAL=console
# Don't probe other OS (pure Debian)
GRUB_DISABLE_OS_PROBER=true
Replace YOUR_CRYPT_UUID with the actual UUID from blkid /dev/nvme0n1p2
6.5 Generate GRUB Configuration
# Re-enter chroot to run update-grub
sudo chroot /mnt/debian /bin/bash
# Generate GRUB config
update-grub
# Verify menu includes encrypted root detection
# Look for lines about crypt_root
# Exit chroot
exit
Phase 7: Install Snapper for APT-Integrated Snapshots (NEW)
We use Snapper (not Timeshift) for automatic snapshot creation before/after every APT operation. This is the key feature of Kali Linux "Unkaputtbar".
# Re-enter chroot
sudo chroot /mnt/debian /bin/bash
# Install Snapper and grub-btrfs
apt update
apt install -y snapper grub-btrfs snapper-gui
# If grub-btrfs unavailable, build from source:
# apt install -y git make
# cd /tmp && git clone https://github.com/Antynea/grub-btrfs.git
# cd grub-btrfs && make install
7.1 Configure Snapper for Root Filesystem
# Create snapper config for root filesystem
# This automatically sets up @.snapshots as the snapshot location
snapper -c root create-config /
# Configure automatic snapshot retention and behavior
#
# RETENTION STRATEGY (APT-integrated snapshots):
# - Automatic snapshots created: 2 per apt operation (pre + post)
# - NUMBER_LIMIT="20" keeps last 20 snapshots = ~10 apt operations
# - NUMBER_LIMIT_IMPORTANT="10" keeps 10 important (manual/tagged) snapshots
# - NUMBER_MIN_AGE="1800" ensures snapshots kept for at least 30 minutes
#
# This provides roughly 1-2 weeks of install history with moderate usage.
# Adjust based on available disk space (each snapshot initially consumes
# ~0 space due to COW, but modifications add unique extents)
cat > /etc/snapper/configs/root << 'EOF'
# Snapper configuration - Kali Linux "Unkaputtbar" style
SUBVOLUME="/"
FSTYPE="btrfs"
# Timeline disabled (we use APT hooks, not time-based snapshots)
TIMELINE_CREATE="no"
TIMELINE_CLEANUP="no"
# Retention settings - enterprise best practice for workstation
NUMBER_LIMIT="20"
NUMBER_LIMIT_IMPORTANT="10"
NUMBER_MIN_AGE="1800"
# Cleanup algorithm
CLEANUP_ALGORITHM="number"
# Sync ACLs for users
SYNC_ACL="yes"
EOF
# Enable the config
echo 'SNAPPER_CONFIGS="root"' > /etc/default/snapper
# Optional: Create separate config for home (optional)
# Home snapshots: 10 total, 5 important (less frequent than root)
# snapper -c home create-config /home
# snapper -c home set-config NUMBER_LIMIT="10" NUMBER_LIMIT_IMPORTANT="5"
# echo 'SNAPPER_CONFIGS="root home"' > /etc/default/snapper
7.2 Configure APT Hooks for Automatic Snapshots (CRITICAL)
This creates automatic pre and post snapshots for every APT operation:
# Create APT hooks for automatic snapshots
mkdir -p /etc/apt/apt.conf.d
# Pre-invoke: Snapshot BEFORE apt operation
cat > /etc/apt/apt.conf.d/80-snapper-pre << 'EOF'
DPkg::Pre-Invoke {
"/usr/bin/snapper -c root create -t pre -d 'apt-pre-'$(date +%Y%m%d-%H%M%S) 2>/dev/null || true;"
};
EOF
# Post-invoke: Snapshot AFTER apt operation (links to pre, auto-cleanup runs)
cat > /etc/apt/apt.conf.d/81-snapper-post << 'EOF'
DPkg::Post-Invoke {
"/usr/bin/snapper -c root create -t post -d 'apt-post-'$(date +%Y%m%d-%H%M%S) --pre-number $(/usr/bin/snapper -c root list | grep '| pre ' | tail -1 | awk '{print $1}') 2>/dev/null || true;"
};
EOF
# Enable snapper cleanup timer (auto-runs daily to enforce retention limits)
systemctl enable snapper-cleanup.timer
systemctl start snapper-cleanup.timer
# Verify hooks
ls -la /etc/apt/apt.conf.d/80* /etc/apt/apt.conf.d/81*
# Test: apt update should trigger pre snapshot
apt update | grep -i snapper || echo "Snapper will snapshot on next apt install/remove/upgrade"
How it works: Every apt install, apt remove, or apt upgrade now automatically:
- Creates a "pre" snapshot (before the operation)
- Runs the APT operation
- Creates a "post" snapshot (linked to the pre snapshot)
If the operation breaks something, boot into the "pre" snapshot and rollback!
7.3 Desktop Manager Subvolumes (Required for Snapper)
When booting into read-only snapshots, GDM needs write access to /var/lib/gdm3 and AccountsService. We created the subvolumes in Phase 3; now we ensure they're properly set up with data migration if needed:
# Create AccountService subvolume if not already created
mkdir -p /mnt/btrfs-root
mount -o subvol=/ /dev/mapper/crypt_root /mnt/btrfs-root
btrfs subvolume create /mnt/btrfs-root/@var_lib_AccountsService 2>/dev/null || echo "Already exists"
umount /mnt/btrfs-root
# IMPORTANT: If GDM was already installed before this step,
# migrate existing data to the subvolumes BEFORE they get mounted
# Check if GDM data exists in root and needs migration
if [ -d "/var/lib/gdm3" ] && [ "$(ls -A /var/lib/gdm3 2>/dev/null)" ]; then
echo "GDM data found in /var/lib/gdm3 - backing up to subvolume..."
mkdir -p /mnt/temp-gdm3
mount -o subvol=@var_lib_gdm3 /dev/mapper/crypt_root /mnt/temp-gdm3
cp -a /var/lib/gdm3/* /mnt/temp-gdm3/ 2>/dev/null || true
umount /mnt/temp-gdm3
fi
# Same for AccountsService
if [ -d "/var/lib/AccountsService" ] && [ "$(ls -A /var/lib/AccountsService 2>/dev/null)" ]; then
echo "AccountsService data found - migrating to subvolume..."
mkdir -p /mnt/temp-accounts
mount -o subvol=@var_lib_AccountsService /dev/mapper/crypt_root /mnt/temp-accounts
cp -a /var/lib/AccountsService/* /mnt/temp-accounts/ 2>/dev/null || true
umount /mnt/temp-accounts
fi
# Update fstab with the new subvolume
UUID=$(blkid -s UUID -o value /dev/mapper/crypt_root)
echo "UUID=$UUID /var/lib/AccountsService btrfs subvol=@var_lib_AccountsService,compress=zstd:1,noatime,autodefrag 0 0" >> /etc/fstab
# For LightDM (if used instead of GDM):
echo "# For LightDM snapshot support:"
echo "sed -i 's/^#user-authority-in-system-dir=false/user-authority-in-system-dir=true/' /etc/lightdm/lightdm.conf"
# Test the mounts
mount -a || echo "Check fstab for errors"
ls -la /var/lib/gdm3 /var/lib/AccountsService 2>/dev/null || echo "Directories will be created on first boot"
7.4 Enable grub-btrfs Daemon
# Enable grub-btrfsd to regenerate boot menu when snapshots change
systemctl enable grub-btrfsd || true
# Create first manual snapshot to test system
snapper -c root create -d "First Boot - Clean Install"
# Update GRUB to detect the new snapshot
update-grub
Snapper tip: Snapper snapshots are stored in @.snapshots, not included in the root snapshot. This keeps system snapshots clean.
Phase 8: Desktop Environment (Wayland-Only GNOME)
Configure GNOME for pure Wayland—no X11 fallback for modern applications.
8.1 Install GNOME (Minimal)
# Install GNOME desktop with minimal bloat
apt install -y \
gnome-core \
gnome-session-wayland \
gdm3 \
xwayland \
pipewire \
pipewire-pulse \
wireplumber \
polkitd \
switcheroo-control
# Remove unnecessary X11 components
apt purge -y xserver-xorg-* || true
# Ensure GDM uses Wayland
cat > /etc/gdm3/custom.conf << 'EOF'
[daemon]
WaylandEnable=true
DefaultSession=gnome-wayland.desktop
[security]
DisallowTCP=true
[xss-server]
EOF
8.2 Configure Session Management
# Install NetworkManager for proper desktop networking
apt install -y network-manager
# Enable services
systemctl enable NetworkManager
systemctl enable gdm3
# Disable systemd-networkd (conflicts with NM)
systemctl disable systemd-networkd || true
# Modern input stack
apt install -y \
libinput10 \
xserver-xorg-input-libinput
# Configure zram swap (Fedora-style, preferred over swap file on BTRFS)
apt install -y zram-tools
# Enable zram with 50% of RAM (Fedora default)
systemctl enable zramswap
Fedora Zram Strategy: Fedora uses zram instead of swap files on BTRFS. Zram creates compressed swap in RAM with higher performance and no wear on SSD. zstd-compressed swap provides ~2-3x effective capacity. For 16GB RAM with zram, you effectively get 8GB compressed swap without disk I/O.
8.3 Configure zram (Optional but Recommended)
# If zram-tools doesn't auto-configure, manually:
cat > /etc/systemd/zram-generator.conf << 'EOF'
[zram0]
zram-size = min(ram / 2, 4096)
compression-algorithm = zstd
EOF
# Or using Debian's zram-tools default
dpkg-reconfigure zramswap
# Note: zram doesn't support hibernation
8.4 Verify Wayland Session
# After first boot, verify Wayland
echo $XDG_SESSION_TYPE # Should output: wayland
# Check for X11 fallback processes
ps aux | grep Xorg # Should be empty or only Xwayland
# Verify native Wayland apps
flatpak list # If using Flatpak, check for Wayland support
Phase 9: Finalize Boot Configuration
9.1 Verify Boot Files
# Exit chroot first
exit
# Verify ESP contains boot files
ls -la /mnt/debian/boot/efi/EFI/
ls -la /mnt/debian/boot/efi/EFI/debian/
# Verify kernel and initramfs are in /boot
ls -la /mnt/debian/boot/vmlinuz-*
ls -la /mnt/debian/boot/initrd.img-*
9.2 Unmount All Devices
# Unmount in reverse order
sudo umount /mnt/debian/dev/pts
sudo umount /mnt/debian/dev
sudo umount /mnt/debian/proc
sudo umount /mnt/debian/sys
sudo umount /mnt/debian/run
# Unmount subvolumes
sudo umount /mnt/debian/var/log
sudo umount /mnt/debian/var/cache
sudo umount /mnt/debian/var/lib/con*
sudo umount /mnt/debian/.snapshots
sudo umount /mnt/debian/home
sudo umount /mnt/debian/boot/efi
# Finally unmount root
sudo umount /mnt/debian
# Close LUKS
sudo cryptsetup close crypt_root
# Verify
lsblk
Phase 10: First Boot and Verification
10.1 Boot Sequence
- Power on system
- Select Debian from UEFI boot menu (or it boots automatically)
- GRUB menu appears
- Select kernel entry
- Prompt: "Please unlock disk crypt_root:"
- Enter LUKS passphrase
- System continues booting into GNOME
10.2 Verify Installation
# Check filesystem info
sudo btrfs filesystem df /
# List snapper configurations
sudo snapper list -a
# List specific config snapshots
sudo snapper -c root list
# Check compression
sudo btrfs filesystem defragment -c zstd / # Apply compression
# Verify grub-btrfs
sudo cat /boot/grub/grub.cfg | grep -A5 "submenu.*Snap"
# View snapshot disk usage
sudo btrfs filesystem du -s /.snapshots/*
10.3 Test Automatic Snapshots
# Test APT hooks by installing a package
# You should see pre/post snapshot creation in output
sudo apt install -y htop
# Check for new snapshots
sudo snapper -c root list
# Should show:
# 0 | single | | | current
# 1 | pre | | apt-pre-... | Before htop installation
# 2 | post | 1 | apt-post-...| After htop installation
# Remove test package and verify rollback works
sudo apt remove -y htop
10.4 Create First Snapshot
# Create a named snapshot before any changes
sudo snapper -c root create -d "Clean Install - Post-Configuration"
# List to verify
sudo snapper -c root list
# Boot menu should show this snapshot (reboot and hold Shift for GRUB menu)
# Should see "Snapper Snapshots" submenu with your snapshot
10.4 Post-First Boot Configuration
# First, ensure SSH is enabled (critical for remote management)
sudo apt install -y openssh-server
# Enable and start SSH
sudo systemctl enable ssh
sudo systemctl start ssh
# Configure SSH (disable root password login for security)
sudo sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config
# Restart SSH to apply changes
sudo systemctl restart ssh
# Check SSH service status
sudo systemctl status ssh
# Allow SSH through firewall (if using ufw)
sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw enable
# Find your IP address
ip addr show | grep "inet " | head -2
Note: SSH is essential for remote management and recovery. The above commands enable SSH access on port 22. Consider
setting up SSH key authentication for better security.
Phase 11: Rollback Procedure
With writable snapshots, you have multiple recovery options. You can boot into a snapshot, test fixes, install packages, or work normally—then decide whether to rollback or keep the changes.
11.1 Boot into Writable Snapshot (Recovery Mode)
# 1. Reboot system
sudo reboot
# 2. At GRUB menu (hold Shift during boot if menu doesn't appear)
# 3. Select "Bootable Snapshots" submenu
# 4. Choose snapshot by date/description
# 5. Boot normally
Writable Snapshot Behavior: Unlike read-only snapshots (default grub-btrfs behavior), your configured snapshots boot with full read/write access. You can:
- Install packages to test fixes (
apt install<package>)
- Edit configuration files
- Run system updates as a test
- Use the system normally while evaluating stability
- Network works normally for downloading fixes
Changes made in a snapshot are isolated and don't affect the main system until you explicitly rollback.
11.2 Option A: Keep Snapshot as New Root (Promote to Production)
If you've made fixes in the snapshot and want to keep them:
# While booted in the snapshot:
# Create another snapshot of THIS state (optional but recommended)
sudo snapper -c root create -d "Working recovery snapshot - before promotion"
# Mount the parent filesystem to perform the swap
sudo mkdir -p /mnt/parent
sudo mount /dev/mapper/crypt_root /mnt/parent
# Backup current root (just in case)
sudo btrfs subvolume snapshot /mnt/parent/@ /mnt/parent/@pre-rollback-$(date +%Y%m%d_%H%M)
# Delete old root and replace with current snapshot's contents
# Method 1: Full replacement (DESTRUCTIVE)
sudo btrfs subvolume delete /mnt/parent/@
sudo btrfs subvolume snapshot /mnt/parent/@.snapshots/$(ls /.snapshots/) /mnt/parent/@
# Method 2: Safer - rename instead of delete
sudo mv /mnt/parent/@ /mnt/parent/@backup-$(date +%Y%m%d_%H%M)
sudo btrfs subvolume snapshot /mnt/parent/@.snapshots/$(ls /.snapshots/) /mnt/parent/@
# Unmount
sudo umount /mnt/parent
# Reboot to new production system
sudo reboot
11.3 Option B: Restore Original Root (Traditional Rollback)
If you want to discard all changes and return to the original root:
# Boot into the snapshot you want to restore (this boots your chosen snapshot)
# Then run this to make it the new root:
# Mount root filesystem
sudo mkdir -p /mnt/target
sudo mount /dev/mapper/crypt_root /mnt/target
# Navigate to snapshots
cd /mnt/target/@snapshots
# List available snapshots
ls -la
# Rollback: backup current, restore chosen snapshot
sudo mv /mnt/target/@ /mnt/target/@pre-rollback-$(date +%Y%m%d_%H%M)
sudo btrfs subvolume snapshot /mnt/target/@.snapshots/YYYY-MM-DD_HH-MM-SS /mnt/target/@
# Unmount
sudo umount /mnt/target
# Reboot to rolled-back system
sudo reboot
Key Difference from Timeshift: Timeshift creates read-only snapshots by default and rolls back by restoring them to @. This guide configures writable bootable snapshots that you can actually WORK IN before deciding to rollback. Think of it as a "test drive" before committing.
11.4 Automatic LUKS Unlock with TPM2 (Optional)
Modern Fedora systems support automatic LUKS unlock via TPM2. This removes the passphrase prompt on boot while maintaining encryption. The key is sealed to TPM PCR measurements (secure boot state, kernel, initramfs).
# Install TPM2 tools (Debian Trixie/Testing)
apt install -y systemd-cryptsetup tpm2-tools clevis-tpm2
# Check TPM2 availability
tpm2_pcrread | head
systemd-cryptenroll --help | grep -A5 tpm2
# Enroll TPM2 unlock (WARNING: read full documentation first)
# This seals the key to PCR 0,2,7 (firmware, secure boot policy)
# systemd-cryptenroll --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=0+2+7 /dev/nvme0n1p2
# Verify enrolled slots
cryptsetup luksDump /dev/nvme0n1p2 | grep -A5 "Keyslots"
# To disable: systemd-cryptenroll --wipe-slot=tpm2 /dev/nvme0n1p2
Security Consideration: TPM2 auto-unlock binds LUKS to hardware state. A compromised OS could still access the disk if initramfs is malicious. Enable Secure Boot and measure initramfs into PCR for stronger protection. This feature requires systemd v248+ (Debian 12+).
11.4 FIDO2 Key Support (YubiKey) on Debian
Based on Fedora's implementation, Debian Trixie supports FIDO2 hardware keys for LUKS unlock using systemd-cryptenroll—same as modern Fedora Workstation.
# Install FIDO2 support (Debian)
apt install -y libfido2-1 libfido2-dev
# Add FIDO2 module to initramfs
cat > /etc/initramfs-tools/hooks/fido2 << 'EOF'
#!/bin/bash
PREREQ=""
prereqs() {
echo "\$PREREQ"
}
case \$1 in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
copy_exec /usr/lib/x86_64-linux-gnu/libfido2.so.1 /lib/x86_64-linux-gnu/
copy_exec /usr/bin/fido2-token /bin/
EOF
chmod +x /etc/initramfs-tools/hooks/fido2
# Rebuild initramfs
update-initramfs -u -k all
# Enroll FIDO2 key (YubiKey with PIN)
# This adds FIDO2 as additional unlock method alongside passphrase
systemd-cryptenroll --wipe-slot=fido2 --fido2-credential-algorithm=eddsa \
--fido2-device=auto /dev/nvme0n1p2
# You'll be prompted to:
# 1. Enter existing passphrase (to authorize enrollment)
# 2. Touch the YubiKey
# 3. Set a PIN for the FIDO2 credential
# Update crypttab for FIDO2 auto-unlock
cat /etc/crypttab
# Change from:
# crypt_root UUID=xxx none luks,discard
# To:
# crypt_root UUID=xxx none luks,discard,fido2-device=auto
EOF
Fedora Note: This mirrors Fedora's FIDO2 implementation. You can now use a complex password as backup and rely on your YubiKey's short PIN for daily use. Shoulder surfing is mitigated—knowing your PIN alone isn't sufficient without physical possession of the FIDO2 key.
Maintenance and Best Practices
# List snapshot disk usage
sudo btrfs filesystem du -s /.snapshots/*
# Show current retention settings
sudo snapper -c root get-config | grep -E "(NUMBER_LIMIT|CLEANUP)"
# Manual cleanup (snapper cleanup runs automatically on snapshot creation)
# When snapshot count exceeds NUMBER_LIMIT, snapper automatically deletes oldest
# Force immediate cleanup if needed
sudo snapper -c root cleanup number
# Delete specific old snapshots by ID (rarely needed with auto-cleanup)
sudo snapper -c root delete 3
# Delete multiple snapshots
sudo snapper -c root delete 3 4 5
⚠️ IMPORTANT: Snapshot Retention Guidelines
├─ NUMBER_LIMIT="20" (default): Last 20 snapshots (~10 apt operations)
├─ NUMBER_LIMIT_IMPORTANT="10": Last 10 important (manual/tagged)
├─ NUMBER_MIN_AGE="1800": Snapshots kept for 30 minutes minimum
└─ Estimated: ~1-2 weeks of apt history with moderate usage
# Balance filesystem (reclaim space after deletions)
sudo btrfs filesystem defragment -r /
# Scrub for data integrity (run monthly)
sudo btrfs scrub start /
sudo btrfs scrub status /
# Check filesystem balance (should be <80% full for optimal performance)
df -h /
Backup Strategy
Snapshots are not backups—they protect against human error, not hardware failure. Supplement with:
- rsync to external storage for @home
- borg or restic for encrypted cloud backups
- LUKS header backup as completed in Phase 2.3
LUKS Key Management
# Add a YubiKey/TPM as additional key slot (optional)
# cryptsetup luksAddKey /dev/nvme0n1p2 --key-slot 1
# Check key slots
sudo cryptsetup luksDump /dev/nvme0n1p2 | grep -A2 "Keyslots"
# Remove a key slot
# sudo cryptsetup luksRemoveKey /dev/nvme0n1p2 --key-slot 1
Troubleshooting
Issue
Solution
grub-install: error: cannot find EFI directory
ESP not mounted on /boot/efi. Check findmnt /boot/efi
cryptsetup: warning: could not determine mountpoint
Fstab entry malformed. Verify blkid UUIDs match
Boot drops to initramfs prompt
Root device not found. Check etc/crypttab has correct UUID
grub-btrfs menu empty
No snapper snapshots exist. Create one with snapper -c root create -d test
Snapper hooks not triggering
Verify /etc/apt/apt.conf.d/80-snapper-pre exists with correct syntax
GDM fails after rollback to read-only snapshot
Ensure @var_lib_gdm3 and @var_lib_AccountsService subvolumes exist
Wayland session not available
Check systemctl status gdm and /var/log/gdm/
BTRFS out of space
Run btrfs filesystem sync then balance
Performance Considerations
Compared to ext4 + LVM:
- Boot time: +2-3 seconds (LUKS unlock overhead)
- Write throughput: -5-10% (Zstd compression overhead)
- Snapshot creation: Instant vs minutes for LVM
- Snapshot space: COW-only changed blocks vs full copy
- SSD longevity: Improved (no journal writes, compression reduces writes)
Conclusion
You now have a modern Debian workstation with:
- ✅ Military-grade encryption via LUKS2 with Argon2id (Fedora 33+ default)
- ✅ FIDO2 hardware key support (YubiKey) matching Fedora Workstation
- ✅ TPM2 auto-unlock capability for seamless boot
- ✅ Automatic APT snapshots via Snapper hooks (before/after every apt operation)
- ✅ Writable bootable snapshots for testing fixes before rollback
- ✅ Kali "Unkaputtbar" subvolume layout (8+ subvolumes for clean separation)
- ✅ Modern display stack with Wayland-only GNOME
- ✅ Fedora zram swap instead of BTRFS swapfiles
This architecture mirrors enterprise Linux distributions while maintaining Debian's stability and flexibility. The Snapper APT integration transforms system administration—every software change is automatically protected with pre/post snapshots. Broken upgrade? Boot the "pre" snapshot, verify it works, then rollback. Snapshots become disposable test environments, not just recovery points.
Key improvements in this guide: Kali Linux "Unkaputtbar" @.snapshots convention, snapper with APT hooks, grub-btrfs for boot menu integration, full systemd-cryptenroll support for TPM2/FIDO2, and writable bootable snapshot promotion workflow. These bring Debian in line with modern Fedora and Kali Linux workstation capabilities.
Next steps: Consider extending this with AppArmor profiles for Mandatory Access Control, or Unified Kernel Images for measured boot with TPM.
About This Guide
This methodology was developed through production deployment experience. If you encounter issues or have optimizations, the grub-btrfs project and BTRFS documentation are authoritative references.
Training available: I teach this material hands-on. Book a session if you need guided implementation.
Book Training Session