I like having a safety net whenever I’m doing something potentially destructive, which is why I use the btrfs file system for my operating system and my data. Snapshots are one half of my “whoops, there goes all my work” strategy (backups are the other half).

I’ve written about how I use snapshots on btrfs using snapper, but lately I’ve become annoyed with it.

Snapshots: probably invented by a developer who owns a cat.
Snapshots: probably invented by a developer who owns a cat.

Shortcomings of snapper

snapper is great while you’re on the happy path, but when you wander off of it, it gets a bit frustrating. This is 100% my own personal experience and I cannot rule out any PEBCAK scenarios, but it’s how I felt using the tool.

The snapshots are on the same subvolume, such as /home/.snapshots, which means that I have to specifically exclude the .snapshots folder in every tool and script that I use for making backups. Without that change, the tools ended up scanning the folder and eating up a lot of resources, mainly the CPU and storage.

Backing up snapshots to something like an external backup SSD wasn’t something that snapper supported out of the box as well, meaning that for offline backups I still had to resort to a good old rsync copy. It’s inconvenient and I won’t have a backup that also contained recent snapshots, but it was manageable.

I also reinstalled Fedora Linux on my ThinkPad recently to see how well my Ansible playbooks hold up (quite decently!) and found that setting up snapper is a bit of a pain. I tried to set up snapper again, but it wasn’t as straightforward as I was hoping for, with it not properly picking up the configuration file changes. At the end, it just ran into weird errors when I tried it to prune some snapshots according to the policy I set up. Since I was running out of disk space, I just gave up, uninstalled snapper and destroyed the snapshots manually.

After all that (and a recommendation by a friend) I decided to bite the bullet and try out btrbk.

btrbk

Setting up btrbk on Fedora Linux 36 was a breeze. Install it via dnf install btrbk, copy your configuration to /etc/btrbk/, make sure that the directory used for snapshots exists with mkdir /btrbk_snapshots and you’re good to go! btrbk is just a huge Perl script, so no fancy dependencies are needed.

My btrfs filesystem has three subvolumes: /, /home and /storage. Data stored on these subvolumes has different levels of importance, which is also reflected in the snapshot retention policies.

The configuration on my setup is the following:

timestamp_format        long

volume /
  snapshot_dir /btrbk_snapshots
  subvolume /
    snapshot_preserve_min   12h
    snapshot_preserve       24h
  subvolume /home
    snapshot_preserve_min   48h
    snapshot_preserve       7d
  subvolume /storage
    snapshot_preserve_min   6h
    snapshot_preserve       7d

To take the snapshots, I’ve set up a systemd timer that runs every 5 minutes and runs the following command:

btrbk -c /etc/btrbk/btrbk.conf run --progress

A successful run will have output like this:

--------------------------------------------------------------------------------
Backup Summary (btrbk command line client, version 0.32.1)
    Date:   Sat Jul  9 14:00:00 2022
    Config: /etc/btrbk/btrbk.conf
Legend:
    ===  up-to-date subvolume (source snapshot)
    +++  created subvolume (source snapshot)
    ---  deleted subvolume
    ***  received subvolume (non-incremental)
    >>>  received subvolume (incremental)
--------------------------------------------------------------------------------
/
+++ /btrbk_snapshots/ROOT.20220709T1400
--- /btrbk_snapshots/ROOT.20220708T1300
/home
+++ /btrbk_snapshots/home.20220709T1400
/storage
+++ /btrbk_snapshots/storage.20220709T1400
--- /btrbk_snapshots/storage.20220709T0745
--- /btrbk_snapshots/storage.20220709T0750
--- /btrbk_snapshots/storage.20220709T0755

I love how the output is very concise about what it just did.

To make a backup of my drive to an external SSD that’s also a btrfs filesystem, I created a separate config at /etc/btrbk/backup-to-ext-drive.conf:

timestamp_format        long

target_preserve_min    no
target_preserve        7d

volume /
  snapshot_dir /btrbk_snapshots
  target /mnt/backup/T430
  subvolume /
  subvolume /home
  subvolume /storage

In this example, /mnt/backup/T430 is a btrfs subvolume itself.

Instead of running rsync, my backup script contains the line:

btrbk -c /etc/btrbk/backup-to-ext-drive.conf run --progress

I love how the default behaviour in btrbk is to keep snapshots separate from the subvolumes themselves. Making a full copy of /home or any other filesystem doesn’t require me to always exclude the .snapshots directory, which is nice.

The snapshot names themselves are also human readable. If I accidentally messed up and my changes from an hour ago were lost, I’d just have to go to /btrbk_snapshots, look up a snapshot from an hour ago, and copy whatever I need from the snapshot. This has already saved my butt at least once.

Conclusion

It’s not often that a piece of software gets me that excited, but btrbk has somehow managed to do it. It’s a single script that has all the example use cases documented in its README and the functionality does exactly what I want.

That’s all I really need from software.

Huge thanks to Digital Integrity GmbH for building, maintaining and sharing this tool with the world!