Using Btrfs Snapshots on Fedora: Fast System Backup and Rollback

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

Get It Done in 5 Minutes — No Complex Setup Required

If your machine is running Fedora 33 or later, the root filesystem is already Btrfs by default. That means you can create a snapshot right now without installing anything extra.

Quickly check if you’re already using Btrfs:

df -T /
# The Type column should show "btrfs"

Create a read-only snapshot of the root subvolume:

# Create the snapshots directory (only needs to be done once)
sudo mkdir -p /.snapshots

# Create a snapshot named by date and time
sudo btrfs subvolume snapshot -r / /.snapshots/root-$(date +%Y%m%d-%H%M)

Verify the snapshot was created:

sudo btrfs subvolume list / | grep snapshots

Done — you now have a full backup of your system state. If you need to recover a file later, just mount this snapshot and copy it out.

Why You Need Snapshots — A Real-World Story

I’ve been using Fedora as my primary development machine for two years and I really appreciate its fast package update cycle. But precisely because Fedora moves fast, occasionally a package upgrade breaks something that was working fine. The most common culprits are NVIDIA drivers or a Python library with an ABI change.

Before discovering snapshots, every incident meant hours of debugging. Now it’s much simpler: take a snapshot before running dnf upgrade, and if something breaks, roll back in a few minutes — no harm done.

How Do Snapshots Work?

A Btrfs snapshot doesn’t copy all your data — it uses a Copy-on-Write (CoW) mechanism. When you create a snapshot, Btrfs simply records the current state by referencing existing data blocks. Only when you modify a file afterward does Btrfs actually copy the old block to a new location and write the new data there.

Thanks to this mechanism, snapshots complete in under a second and initially consume almost no additional space. Storage usage only grows gradually as the system changes over time.

Compared to Traditional Backups

  • Creation speed: Btrfs snapshots complete in under a second. An rsync backup takes tens of minutes.
  • Initial storage size: A snapshot takes nearly 0 bytes when first created. A copy-based backup doubles your data immediately.
  • Limitations: Snapshots only work within the same Btrfs filesystem. Backing up to an external drive still requires additional tools.

Using Snapper for Automation — Set It Up Once, It Runs Forever

Creating snapshots manually is fine for your first try, but in practice you’ll forget to do it before running a risky command. Snapper solves that problem — it manages snapshots and, most importantly, integrates with DNF to automatically capture the system state before and after every update.

Installing Snapper and the DNF Plugin

sudo dnf install snapper python3-dnf-plugin-snapper

Create a Snapper configuration for the root subvolume:

sudo snapper -c root create-config /

View the default configuration that was just created:

sudo snapper -c root get-config

Creating Snapshots Manually with Snapper

# Create a snapshot with a description
sudo snapper -c root create --description "Before testing Nginx config"

# List all snapshots
sudo snapper -c root list

The output will look like this:

  # | Type   | Pre # | Date                      | User | Description
----+--------+-------+---------------------------+------+-------------------------
  0 | single |       |                           | root | current
  1 | single |       | 2025-03-15 09:30:12 +0900 | root | Before testing Nginx config

Automatic Snapshots When Running dnf

After installing python3-dnf-plugin-snapper, the plugin will automatically create a “pre” and “post” snapshot pair every time you run dnf. No additional configuration needed:

sudo dnf upgrade
# Snapper automatically creates a "pre" snapshot before the upgrade begins
# And a "post" snapshot after it completes

Check the results after the upgrade completes:

sudo snapper -c root list
# You'll see the pre/post snapshot pair with types "pre" and "post"

Comparing Changes Between Two Snapshots

The feature I use most is checking which files changed after an upgrade — especially useful when you need to know which config files were overwritten:

# Compare snapshot 3 (pre) and snapshot 4 (post)
sudo snapper -c root status 3..4

# View detailed diff of a specific file
sudo snapper -c root diff 3..4 /etc/nginx/nginx.conf

Rolling Back When Something Goes Wrong

Rolling Back a Specific File — Fastest Fix for Minor Issues

Accidentally deleted a file or broke a config after editing it:

# Restore a specific file from snapshot 1 to the current state (0)
sudo snapper -c root undochange 1..0 /etc/fstab

# Or manually mount the snapshot and copy the file
sudo mount -o ro,subvol=/.snapshots/1/snapshot /dev/sda3 /mnt
cp /mnt/etc/fstab /etc/fstab
sudo umount /mnt

Full System Rollback via GRUB

For more serious situations — the new kernel won’t boot, or an upgrade broke the desktop environment. Install grub-btrfs so GRUB shows a menu for booting into a snapshot:

sudo dnf install grub-btrfs
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Reboot, and GRUB will have a new “Fedora snapshots” entry to boot into an old snapshot. Once you’ve successfully booted into the snapshot you want to keep:

sudo snapper rollback
sudo reboot

Note: snapper rollback works best when the subvolume layout follows the Snapper standard. With Fedora’s default layout (subvolumes @ and @home), you should check Snapper’s documentation to verify compatibility before using this in a production environment.

Practical Tips for Sustainable Snapshot Usage

Create an Alias for the Snapshot-Before Habit

Add to ~/.bashrc to quickly take a snapshot before any risky operation:

# Add to ~/.bashrc
alias snap-now='sudo snapper -c root create --description "Manual: $(date +%Y%m%d-%H%M)"'

# Reload bashrc
source ~/.bashrc

# Usage: snap-now && sudo dnf upgrade

Managing Disk Space — Don’t Let Snapshots Fill Your Drive

After a few weeks of regular updates, /.snapshots can consume 5–20 GB depending on how much the system changes. Configure Snapper’s timeline cleanup to keep a reasonable number of snapshots:

sudo snapper -c root set-config \
  TIMELINE_CREATE=yes \
  TIMELINE_LIMIT_HOURLY=5 \
  TIMELINE_LIMIT_DAILY=7 \
  TIMELINE_LIMIT_WEEKLY=2 \
  TIMELINE_LIMIT_MONTHLY=1 \
  TIMELINE_LIMIT_YEARLY=0

Delete old snapshots you no longer need:

# Delete snapshot number 5
sudo snapper -c root delete 5

# Delete multiple snapshots at once
sudo snapper -c root delete 3-8

# Check how much space snapshots are using
sudo btrfs filesystem du -s /.snapshots/*

Backing Up Snapshots to an External Drive with btrfs send

Snapshots on the same drive only protect you from software failures, not hardware failures. For true off-device backup, use btrfs send to send snapshots to an external drive:

# Assume the external drive is mounted at /backup (must be a Btrfs filesystem)
# Send a full snapshot
sudo btrfs send /.snapshots/1/snapshot | sudo btrfs receive /backup/

# Send incremental — only the changes since the previous snapshot, extremely fast
sudo btrfs send -p /.snapshots/1/snapshot /.snapshots/2/snapshot | \
  sudo btrfs receive /backup/

Incremental backups only transfer the data that changed between two snapshots — instead of copying tens of gigabytes, you’re transferring just a few hundred megabytes for each daily backup.

After using this workflow for a while, I barely feel any anxiety before running dnf upgrade. Snapshots take under a second, rollbacks take a few minutes — a trade-off that’s absolutely worth it compared to hours of debugging when something goes wrong.

Share: