Benefits at a Glance
- Fast and reliable system recovery after failed updates or configuration issues
- Minimal data loss thanks to automatic and manual Btrfs snapshots
- Point-in-time rollback from GRUB menu, even before booting the system
- Easy management via Snapper or command line
- Cleaner and safer solution than traditional backup/restore for system volumes
Debian GNU/Linux is known for its stability and reliability. With Debian 13 "Trixie", you get updated packages, better hardware support, and five years of security updates, making it ideal for workstations, servers, and development environments.
But what if you could add a safety net to Debian's stability? Pairing it with the Btrfs filesystem gives you instant snapshots and rollbacks, like an undo button for your entire system. Update broke something? Roll back in seconds. Want to test risky changes? Snapshot first and experiment fearlessly.
Since Debian's graphical installer doesn't yet support custom Btrfs subvolumes, this tutorial uses the debootstrap method to manually build a production-ready system with:
- Btrfs filesystem with optimized subvolume structure
- Snapper for automated snapshot management
- GRUB-Btrfs integration for booting into snapshots
- Swap with hibernation support
- Easy rollback via Btrfs-Assistant
- Desktop environment of your choice
Whether you're a user seeking a resilient daily driver, a sysadmin wanting reliable rollback options, or a developer who experiments often, this guide helps you create a resilient Debian system.
Prerequisites:
- Debian 13 (Trixie) Live ISO: Download the Live ISO (not the standard installation ISO) from the official Debian website.
- Target System: A physical or virtual machine for installing Debian.
- Internet Connection: An active and stable internet connection.
- Disk Space: Minimum 20 GB for the base system; 50 GB or more recommended for a desktop environment and adequate snapshot storage.
Table of Contents
- Step 1: Boot into the Live Environment
- Step 2: Wipe Disk and Create GPT Partitions
- Step 3: Create Essential Btrfs Subvolumes
- Step 4: Mount the Subvolumes for Installation
- Step 5: Install the Debian 13 Base System with debootstrap
- Step 6: Configure fstab
- Step 7: Chroot into the Installed System
- Step 8: Configure Base System Settings
- Step 9: Configure Repositories and Install Base Packages
- Step 10: Create Swap with Hibernation Support
- Step 11: Create a User
- Step 12: Install and Configure GRUB Bootloader
- Step 13: Exit Chroot and Reboot
- Step 14: Install the Desktop Environment
- Step 15: Create a .mozilla Subvolume in Home
- Step 16: Install and Configure Snapper
- Step 17: Install GRUB-Btrfs
- Step 18: Enable Automatic Timeline Snapshots
- Step 19: Test Your Snapshot and Rollback Setup
- Conclusion
- Watch on YouTube
Step 1: Boot into the Live Environment
Boot from the Debian 13 Live ISO or USB.
I’ll be using the Debian GNOME Live edition since I’m setting up a GNOME desktop, but you can use any Debian Live edition. The choice of Live ISO doesn’t affect the final system. You can still install any desktop environment using the debootstrap method.
Once on the desktop, open a terminal and switch to the root user to prepare for installation.
sudo su
Run the following command to list all available disks:
lsblk -p
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
/dev/loop0 7:0 0 3.1G 1 loop /run/live/rootfs/filesystem.squashfs
/dev/sda 8:0 0 128G 0 disk
/dev/sr0 11:0 1 3.8G 0 rom /run/live/medium
This displays all your disks and their partitions. Identify the disk where you want to install Debian.
Next, set a variable for your target disk. For example:
export DISK="/dev/sda"
In this tutorial, I’m using /dev/sda, but replace it with the disk you want to install Debian on.
Warning: This tutorial assumes you will be using the entire disk stored in the DISK variable for installation. All data on that disk will be erased. Make sure you have backed up any important files before proceeding.
Note: From this point onward, all commands in each code block are formatted so you can copy the entire block and paste it directly into your terminal, then press Enter. You don’t need to copy and run each command individually, which helps avoid typos and speeds up the installation process.
Step 2: Wipe Disk and Create GPT Partitions
First, we need to wipe the disk, create a fresh GPT layout, and set up the EFI and root partitions. The gdisk tool is required for this, but it is not installed in the Live environment by default.
apt update && apt install gdisk -y
Warning: These commands will erase all data on $DISK. Make sure you selected the correct disk.
# Wipe the disk and create a fresh GPT layout
sgdisk -Z $DISK
sgdisk -og $DISK
# Create EFI system partition (1 GiB)
sgdisk -n 1::+1G -t 1:ef00 -c 1:'ESP' $DISK
# Create root partition (rest of the disk)
sgdisk -n 2:: -t 2:8300 -c 2:'LINUX' $DISK
# Format the EFI partition with FAT32 filesystem
mkfs.fat -F32 -n EFI ${DISK}1
# Format the main partition with Btrfs filesystem
mkfs.btrfs -L DEBIAN ${DISK}2
# Verify the filesystem formats
lsblk -po name,size,fstype,fsver,label,uuid $DISK
You should now see the filesystem layout something like this:
NAME SIZE FSTYPE FSVER LABEL UUID
/dev/sda 128G
├─/dev/sda1 1G vfat FAT32 EFI 3C4B-6CAA
└─/dev/sda2 127G btrfs DEBIAN c499d0e9-f65b-418d-865d-defa9ff397aa
Step 3: Create Essential Btrfs Subvolumes
We’ll now create the main Btrfs subvolumes that separate system files, user data, and temporary data. This layout ensures snapshots stay efficient and prevent rollback issues caused by temporary or volatile files.
# Mount the Btrfs root
mount -v ${DISK}2 /mnt
# Create essential subvolumes
btrfs subvolume create /mnt/@ # Root filesystem
btrfs subvolume create /mnt/@home # User home data
btrfs subvolume create /mnt/@opt # Optional software
btrfs subvolume create /mnt/@cache # Cache data
btrfs subvolume create /mnt/@gdm3 # Display manager data (GNOME)
btrfs subvolume create /mnt/@libvirt # Virtual machines
btrfs subvolume create /mnt/@log # Log files
btrfs subvolume create /mnt/@spool # Spool data
btrfs subvolume create /mnt/@tmp # Temporary files
btrfs subvolume create /mnt/@swap # Swap file location
# Unmount when done
umount -v /mnt
Note: Create the subvolume matching your display manager.
For GNOME use @gdm3, for KDE use @sddm, and for XFCE use @lightdm. Only one is required depending on your desktop environment.
Step 4: Mount the Subvolumes for Installation
Now that we have created all the Btrfs subvolumes, we need to mount them to their proper directories before installing Debian. This ensures that each subvolume is used for the right purpose during installation and that Snapper can manage snapshots correctly.
# Define mount options for optimal Btrfs performance
BTRFS_OPTS="defaults,noatime,space_cache=v2,compress=zstd:1"
# Mount the root subvolume
mount -vo $BTRFS_OPTS,subvol=@ ${DISK}2 /mnt
# Create directories for other subvolumes
mkdir -vp /mnt/{home,opt,boot/efi,var/{cache,lib/{gdm3,libvirt},log,spool,tmp,swap}}
# Mount the remaining subvolumes
mount -vo $BTRFS_OPTS,subvol=@home ${DISK}2 /mnt/home
mount -vo $BTRFS_OPTS,subvol=@opt ${DISK}2 /mnt/opt
mount -vo $BTRFS_OPTS,subvol=@cache ${DISK}2 /mnt/var/cache
mount -vo $BTRFS_OPTS,subvol=@gdm3 ${DISK}2 /mnt/var/lib/gdm3
mount -vo $BTRFS_OPTS,subvol=@libvirt ${DISK}2 /mnt/var/lib/libvirt
mount -vo $BTRFS_OPTS,subvol=@log ${DISK}2 /mnt/var/log
mount -vo $BTRFS_OPTS,subvol=@spool ${DISK}2 /mnt/var/spool
mount -vo $BTRFS_OPTS,subvol=@tmp ${DISK}2 /mnt/var/tmp
# Mount swap subvolume without compression or CoW for reliability
mount -vo defaults,noatime,subvol=@swap ${DISK}2 /mnt/var/swap
# Mount the EFI partition
mount -v ${DISK}1 /mnt/boot/efi
# Verify the mounts
lsblk -po name,size,fstype,uuid,mountpoints $DISK
Desktop environments:
- For KDE, replace
@gdm3with@sddmand mount to/mnt/var/lib/sddm.- For XFCE, use
@lightdmand mount to/mnt/var/lib/lightdm.
Your /mnt directory should now reflect the proper Btrfs layout, with each subvolume mounted to its intended location and ready for Debian installation.
NAME SIZE FSTYPE UUID MOUNTPOINTS
/dev/sda 128G
├─/dev/sda1 1G vfat 3C4B-6CAA /mnt/boot/efi
└─/dev/sda2 127G btrfs c499d0e9-f65b-418d-865d-defa9ff397aa /mnt/var/swap
/mnt/var/tmp
/mnt/var/spool
/mnt/var/log
/mnt/var/lib/libvirt
/mnt/var/lib/gdm3
/mnt/var/cache
/mnt/opt
/mnt/home
/mnt
Step 5: Install the Debian 13 Base System with debootstrap
Now that all Btrfs subvolumes are properly mounted, we’ll install the minimal Debian base system onto our mounted root directory using the debootstrap tool. This forms the foundation of your Debian installation before we chroot into it for further configuration.
# Install debootstrap if not already installed
apt install -y debootstrap
# Install base Debian 13 (Trixie) system into /mnt
debootstrap --arch=amd64 trixie /mnt http://deb.debian.org/debian
# Mount necessary filesystems for chroot environment
for dir in dev proc sys run; do
mount -v --rbind "/${dir}" "/mnt/${dir}"
mount -v --make-rslave "/mnt/${dir}"
done
# Mount EFI variables (for UEFI systems)
mount -v -t efivarfs efivarfs /mnt/sys/firmware/efi/efivars
Step 6: Configure fstab
Next, we’ll create the fstab file, which defines how partitions and Btrfs subvolumes are mounted at boot. This ensures each subvolume mounts to the correct directory automatically after installation.
# Get UUIDs for Btrfs and EFI partitions
BTRFS_UUID=$(blkid -s UUID -o value ${DISK}2) ; echo $BTRFS_UUID
EFI_UUID=$(blkid -s UUID -o value ${DISK}1) ; echo $EFI_UUID
# Create /etc/fstab inside the target system
cat > /mnt/etc/fstab << EOF
UUID=$BTRFS_UUID / btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@ 0 0
UUID=$BTRFS_UUID /home btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@home 0 0
UUID=$BTRFS_UUID /opt btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@opt 0 0
UUID=$BTRFS_UUID /var/cache btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@cache 0 0
UUID=$BTRFS_UUID /var/lib/gdm3 btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@gdm3 0 0
UUID=$BTRFS_UUID /var/lib/libvirt btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@libvirt 0 0
UUID=$BTRFS_UUID /var/log btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@log 0 0
UUID=$BTRFS_UUID /var/spool btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@spool 0 0
UUID=$BTRFS_UUID /var/tmp btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@tmp 0 0
UUID=$BTRFS_UUID /var/swap btrfs defaults,noatime,subvol=@swap 0 0
UUID=$EFI_UUID /boot/efi vfat defaults,noatime 0 2
EOF
# Verify the fstab file content
cat /mnt/etc/fstab
- For KDE, replace /var/lib/gdm3 and
@gdm3with/var/lib/sddmand@sddm.- For XFCE, use
/var/lib/lightdmand@lightdm.
The fstab file should look similar to this, though the UUIDs will differ on your system.
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa / btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@ 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /home btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@home 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /opt btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@opt 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /var/cache btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@cache 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /var/lib/gdm3 btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@gdm3 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /var/lib/libvirt btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@libvirt 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /var/log btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@log 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /var/spool btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@spool 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /var/tmp btrfs defaults,noatime,space_cache=v2,compress=zstd:1,subvol=@tmp 0 0
UUID=c499d0e9-f65b-418d-865d-defa9ff397aa /var/swap btrfs defaults,noatime,subvol=@swap 0 0
UUID=3C4B-6CAA /boot/efi vfat defaults,noatime 0 2
Step 7: Chroot into the Installed System
Now that the base system and fstab are ready, we’ll enter the new Debian environment using chroot. This allows us to configure the system as if we had booted into it directly.
chroot /mnt /bin/bash
Step 8: Configure Base System Settings
In this step, we’ll set the hostname, update the hosts file, configure the timezone, and generate locales for the system.
Note: The timezone is set to
America/New_York(USA) and the locale toen_US.UTF-8. You should change these to match your location and preferred language when running the commands.
# Set the system hostname
echo "debian" > /etc/hostname
# Configure /etc/hosts
cat > /etc/hosts << EOF
127.0.0.1 localhost
127.0.1.1 $(cat /etc/hostname)
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
# Set the timezone (adjust to your region)
ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime
# Install and configure locales
apt install -y locales
dpkg-reconfigure locales
Step 9: Configure Repositories and Install Base Packages
Now that the system locale and timezone are set, we’ll configure APT sources for Debian 13 (Trixie) and install the kernel, firmware, GRUB, networking tools, and essential utilities.
# Configure APT sources for Debian 13 (Trixie)
cat > /etc/apt/sources.list << EOF
deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian trixie main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware
deb-src http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware
EOF
# Update package lists
apt update
# Install kernel, system tools, and essential utilities
apt install -y linux-image-amd64 linux-headers-amd64 \
firmware-linux firmware-linux-nonfree \
grub-efi-amd64 efibootmgr network-manager \
btrfs-progs sudo vim bash-completion
Step 10: Create Swap with Hibernation Support
We’ll create a swap file on the Btrfs filesystem, disable compression for it, and configure the system so hibernation works correctly.
Note: Hibernation requires Secure Boot to be disabled in BIOS/UEFI settings. The Linux kernel blocks hibernation when Secure Boot is enabled for security reasons. To check:
mokutil --sb-state. If you want to keep Secure Boot enabled, usesudo systemctl suspendinstead.
# Prepare swap file
truncate -s 0 /var/swap/swapfile
chattr +C /var/swap/swapfile # Disable COW
btrfs property set /var/swap compression none # Disable compression
# My system has 4 GB RAM, so I create 6 GB swap for hibernation (1.5× of RAM)
dd if=/dev/zero of=/var/swap/swapfile bs=1M count=6144 status=progress
chmod 600 /var/swap/swapfile
mkswap -L SWAP /var/swap/swapfile
# Add swap to fstab and enable it
echo "/var/swap/swapfile none swap defaults 0 0" >> /etc/fstab
swapon /var/swap/swapfile
swapon -v
# Configure GRUB for hibernation
SWAP_OFFSET=$(btrfs inspect-internal map-swapfile -r /var/swap/swapfile)
BTRFS_UUID=$(blkid -s UUID -o value ${DISK}2)
GRUB_CMD="quiet resume=UUID=$BTRFS_UUID resume_offset=$SWAP_OFFSET"
echo "GRUB_CMDLINE_LINUX_DEFAULT=\"$GRUB_CMD\"" >> /etc/default/grub
# Update GRUB configuration with new kernel parameters
update-grub
# Configure initramfs for hibernation (using swap file)
cat > /etc/initramfs-tools/conf.d/resume << EOF
RESUME=/var/swap/swapfile
RESUME_OFFSET=$SWAP_OFFSET
EOF
# Update initramfs to include hibernation support
update-initramfs -u -k all
Step 11: Create a User
We’ll create a new user, add them to the sudo and adm groups, set their shell, and assign a password. Change the username and full name to match your preference.
# Create a new user (replace with your username and name)
useradd -m -G sudo,adm -s /bin/bash -c "Madhu" madhu
# Set the user password
passwd madhu
# Verify the user creation
id madhu
Step 12: Install and Configure GRUB Bootloader
We’ll install the GRUB bootloader for UEFI systems and generate its configuration so the system can boot correctly.
# Install GRUB for UEFI
grub-install \
--target=x86_64-efi \
--efi-directory=/boot/efi \
--bootloader-id=debian \
--recheck
# Generate GRUB configuration
update-grub
Step 13: Exit Chroot and Reboot
Once all configurations are complete, exit the chroot environment, unmount the partitions, and reboot into your new Debian system.
First, exit the chroot environment:
exit
Once back in the live environment (or host shell), unmount the partitions and reboot:
# Unmount all mounted directories
umount -vR /mnt
# Reboot into the installed system
reboot
Step 14: Install the Desktop Environment
After rebooting, your system will start from the newly installed Debian setup — a minimal command-line environment running independently, not inside the chroot.
Log in with your user account and install your preferred desktop environment. Installing it on the running system is recommended, as it allows all services, drivers, and display components to initialize properly under systemd.
For this guide, I will install GNOME, the default Debian desktop environment:
sudo apt install -y task-gnome-desktop
For KDE and XFCE, use the following commands instead:
# For KDE Desktop
sudo apt install -y task-kde-desktop
# For XFCE Desktop
sudo apt install -y task-xfce-desktop
Once the installation is complete, reboot the system:
sudo reboot
After reboot, you will be logged into Debian 13 with the GNOME 48 desktop environment.

Step 15: Create a .mozilla Subvolume in Home
You might be wondering: “We already have a @home subvolume. Why create another subvolume inside it?”
Here’s why:
- The
@homesubvolume protects your home directory from rollbacks of the root@subvolume, keeping personal files safe when restoring system snapshots. - But what if you want to include
@homein snapshots and undo changes — for example, when testing a new application? Most apps create configuration files throughout your home directory. When you undo changes, all these files are reverted — except you may want to keep some directories intact, like Firefox’s.mozillawith your bookmarks, passwords, and extensions. - Creating a separate
.mozillasubvolume ensures you can safely undo changes in@homewhile keeping important application data untouched. This creates a “water-tight” rollback: test apps freely, revert unwanted changes, and preserve critical personal data.
# Create a subvolume for .mozilla
btrfs subvolume create ~/.mozilla
# Verify the subvolume has been created
sudo btrfs subvolume list /
You should see output similar to this, showing the .mozilla subvolume nested inside @home:
ID 256 gen 66 top level 5 path @
ID 257 gen 66 top level 5 path @home
ID 258 gen 9 top level 5 path @opt
ID 259 gen 66 top level 5 path @cache
ID 260 gen 66 top level 5 path @gdm3
ID 261 gen 9 top level 5 path @libvirt
ID 262 gen 66 top level 5 path @log
ID 263 gen 65 top level 5 path @spool
ID 264 gen 66 top level 5 path @tmp
ID 265 gen 30 top level 5 path @swap
ID 266 gen 67 top level 257 path @home/madhu/.mozilla
Note: I have only created .mozilla as an example. If you use a different browser or have other important directories (like project directories) inside your home subvolume, I recommend creating separate subvolumes for them in the same way to keep them safe from rollbacks.
Step 16: Install and Configure Snapper
Snapper is a tool that manages Btrfs snapshots, allowing you to easily take snapshots, compare changes, and undo modifications. In this step, we’ll install Snapper, create configurations for both the root (@) and home (@home) subvolumes, and adjust settings for safe usage.
# Install Snapper and required tools
sudo apt install -y snapper btrfs-assistant inotify-tools git make
# Create Snapper config for root (@) and home (@home) subvolumes
sudo snapper -c root create-config /
sudo snapper -c home create-config /home
# Grant user access and synchronize ACLs
sudo snapper -c root set-config ALLOW_USERS=$USER SYNC_ACL=yes
sudo snapper -c home set-config ALLOW_USERS=$USER SYNC_ACL=yes
# List available Snapper configs
sudo snapper list-configs
# Show current settings for root and home
snapper -c root get-config
snapper -c home get-config
# List snapshots for root and home
snapper ls
snapper -c home ls
Note: At this stage, you do not have any snapshots yet. Snapshots will be created later either manually or automatically when timeline or boot timers are active.
Step 17: Install GRUB-Btrfs
GRUB-Btrfs integrates your Btrfs snapshots with the GRUB bootloader. This allows you to boot directly into snapshots created by Snapper, making rollback easy and safe.
Navigate to a temporary directory:
cd /tmp
Install GRUB-Btrfs:
# Clone the GRUB-Btrfs repository from GitHub
git clone https://github.com/Antynea/grub-btrfs.git
cd grub-btrfs
# Edit the configuration to set kernel parameters for snapshots
sed -i.bkp \
'/^#GRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS=/a \
GRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS="rd.live.overlay.overlayfs=1"' \
config
# Install GRUB-Btrfs
sudo make install
# Enable and start the GRUB-Btrfs daemon to update
# GRUB automatically when snapshots are created
sudo systemctl enable --now grub-btrfsd.service
Step 18: Enable Automatic Timeline Snapshots
Snapper can automatically create snapshots at key intervals: every system boot, every hour, and perform daily cleanup of old snapshots.
By default, automatic snapshots for timelines, boot, and cleanup are already enabled.
You can check their status with these commands:
sudo systemctl status snapper-boot.timer
sudo systemctl status snapper-timeline.timer
sudo systemctl status snapper-cleanup.timer
Here’s what each timer does:
snapper-boot.timer– Automatically creates a snapshot of the root subvolume at every system boot, giving a safe rollback point if the system fails to start.snapper-timeline.timer– By default, takes snapshots every hour for configured subvolumes, tracking changes over time.snapper-cleanup.timer– By default, runs once per day to remove old snapshots according to Snapper’s retention policies, keeping disk usage under control.
To customize the frequency, you can edit the timer files located in /usr/lib/systemd/system/ or override them in /etc/systemd/system/. See the Snapper Arch Wiki for examples.
By default, timeline snapshots are enabled for both root (@) and home (@home) subvolumes. However, it is recommended to keep timeline snapshots enabled only for root and disable them for home to avoid excessive snapshot clutter:
sudo snapper -c home set-config TIMELINE_CREATE=no
Why disable timeline snapshots for home?
Home directories often contain large amounts of personal files and frequently changing data. Enabling automatic timeline snapshots for home can quickly create hundreds of snapshots, using up disk space and making snapshot management cumbersome. Disabling it for home keeps snapshots focused on the system (@), while still allowing manual snapshots for important home directories when needed.
Step 19: Test Your Snapshot and Rollback Setup
Now that everything is configured, it’s time to verify that your snapshot and rollback system works correctly. These tests were originally performed on Fedora 40, but they apply to Debian as well. Simply use apt instead of dnf.
Tip: If you are running Debian in a virtual machine, it is highly recommended to perform these tests first. This helps you build confidence in your snapshot system before relying on it for important work.
Here are some safe and practical tests you can try:
- Test 1: Undo the Changes Made by the DNF Installer. Learn how to revert all changes made when installing or removing packages. This is perfect for cleaning up after testing new software.
- Test 2: Undo Any Changes Made to Individual Files. Practice reverting changes to individual system files. This is useful when a configuration edit breaks something.
- Test 3: Create Manual Pre-Post Snapshots and Undo the Changes. Create manual pre and post snapshots before making risky changes, then roll back safely. This forms the foundation of fearless system experimentation.
- Test 4: Rollback Using Btrfs Assistant GUI. Use the graphical Btrfs Assistant tool to browse snapshots and perform rollbacks without command-line complexity.
Conclusion
That’s it – this concludes the step-by-step tutorial for installing Debian 13 with a Btrfs filesystem, Snapper snapshots, and GRUB-Btrfs integration. You now have a resilient system with:
- A fully functional Debian 13 installation
- Btrfs subvolumes optimized for snapshots and rollbacks
- Snapper configured for safe system and home snapshots
- GRUB-Btrfs integration for booting into snapshots
- Timeline and boot snapshots configured for convenience and safety
With this setup, you can experiment, test applications, and update your system confidently, knowing you can always roll back to a previous state without losing important data. Your home directories, including critical application data like Firefox profiles, remain safe even during system rollbacks.
You now have a robust Debian 13 system with Btrfs snapshots and rollback support, perfect for safe updates and easy recovery.


Buy Me a Coffee