sudo apt -y install software-properties-common
Manually taking snapshots with Btrfs is easy. Managing said snapshots is not. This is why several tools exist for the task. The most prominent are Btrbk, Snapper, and Timeshift. Each of these automate taking, naming, and cleaning up snapshots. Btrbk is highly configurable and flexible while also offering incremental backups. It doesn’t handle rollbacks, however. Timeshift is only designed for rolling back a system’s root subvolume and not arbitrary subvolumes. It is rather inflexible, but provides a fantastic graphical interface right out of the box and makes rollbacks quick and easy. Snapper is very configurable, makes rollbacks a breeze, has been around a while, and is quite popular. It’s a bit biased towards openSUSE, it being their tool and all, but packaged for all major Linux distributions nonetheless. My choice was mostly between Btrbk and Snapper. Timeshift won’t snapshot all of the subvolumes I have. I landed on Snapper because it allows users to control their own snapshots and rollbacks without superuser privileges. Btrbk’s additional ability for managing backups makes it a very tempting alternative.
This tutorial contains the necessary steps to setup a recent version of Snapper to take automatic snapshots of a system’s root directory and a user’s home directory using Btrfs. The reference system is running elementary OS 5.1 and uses a {flat-btrfs-layout} for the system’s subvolumes. The layout is discussed extensively in Btrfs Layout. For this tutorial, you should understand the command-line, Btrfs, and the filesystem layout used in Linux. As a matter of preference, the commands here use the fish shell's syntax.
The version of Snapper packaged by my distribution lags significantly behind the upstream version. Fortunately, Snapper makes newer versions readily available through its own PPA. To install Snapper this way, follow these instructions.
Install the necessary package for easily adding PPA’s.
sudo apt -y install software-properties-common
Add the Snapper repository for Ubuntu 18.04, off which elementaryOS Hera 5.1 is based, to the system’s sources.
echo 'deb http://download.opensuse.org/repositories/filesystems:/snapper/xUbuntu_18.04/ /' \
| sudo tee /etc/apt/sources.list.d/filesystems:snapper.list
deb http://download.opensuse.org/repositories/filesystems:/snapper/xUbuntu_18.04/ /
Trust the repository’s GPG key.
wget -qO - https://download.opensuse.org/repositories/filesystems:/snapper/xUbuntu_18.04/Release.key \
| gpg --dearmor \
| sudo tee /etc/apt/trusted.gpg.d/filesystems_snapper.gpg > /dev/null
Refresh the package sources.
sudo apt update
Install Snapper.
sudo apt -y install snapper
To avoid potential slowdowns, exclude any .snapshots
subvolumes in updatedb.conf(5)
so that they aren’t indexed by mlocate(1)
.
PRUNENAMES = ".snapshots"
For each subvolume you want to snapshot, create a separate subvolume within it to hold the snapshots.
This prevents snaphots being included in snapshots.
Snapper uses a .snapshots
subvolume by convention.
The steps below create a .snapshots
subvolume in which to keep snapshots of the root subvolume.
The subvolume is created according to a flat layout, so it exists at the top-level of the Btrfs volume and is mounted explicitly in fstab(5).
Mount the volume containing the root subvolume to /mnt
.
sudo mount (df --output=source / | tail -n 1) /mnt
Create a btrfs subvolume where the snapshots will be stored.
Here the subvolume will be named snapshots
.
If you prefer to prefix the name with @
, be my guest.
sudo btrfs subvolume create /mnt/snapshots
Add an entry in fstab to mount the snapshots subvolume.
echo (df --output=source / | tail -n 1)" /.snapshots btrfs defaults,autodefrag,compress=zstd,commit=120,noatime,subvol=snapshots 0 0" \
| tee -a /etc/fstab
Mount the snapshots subvolume.
sudo mount /.snapshots
Unmount /mnt.
sudo umount /mnt
Configuration of Snapper is done through a config file. One config file is used for each subvolume that Snapper will snapshot. Typically, a new Snapper configuration is generated with a single command given the name for the config and the path of the subvolume to snapshot. A configuration for the root subvolume, aptly named root, would be generated as shown here.
sudo snapper -c root create-config /
Due to some sort of misconfiguration or bug, the create-config
subcommand fails.
The instructions below create a config manually as a workaround.
Create a root config file by copying the template file to the configs directory.
cp /etc/snapper/config-templates/default /etc/snapper/configs/root
Edit the config file to your liking.
Below is an example of a root config which uses the timeline features of Snapper to create and cleanup snapshots.
The entire configuration file is included but the TIMELINE_
variables are the most important.
They enable automatically creating and removing snapshots and designate how many snapshots to retain for a particular period.
# subvolume to snapshot
SUBVOLUME="/"
# filesystem type
FSTYPE="btrfs"
# btrfs qgroup for space aware cleanup algorithms
QGROUP=""
# fraction of the filesystems space the snapshots may use
SPACE_LIMIT="0.5"
# fraction of the filesystems space that should be free
FREE_LIMIT="0.2"
# users and groups allowed to work with config
ALLOW_USERS=""
ALLOW_GROUPS=""
# sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
# directory
SYNC_ACL="no"
# start comparing pre- and post-snapshot in background after creating
# post-snapshot
BACKGROUND_COMPARISON="yes"
# run daily number cleanup
NUMBER_CLEANUP="yes"
# limit for number cleanup
NUMBER_MIN_AGE="1800"
NUMBER_LIMIT="50"
NUMBER_LIMIT_IMPORTANT="10"
# create hourly snapshots
TIMELINE_CREATE="yes"
# cleanup hourly snapshots after some time
TIMELINE_CLEANUP="yes"
# limits for timeline cleanup
TIMELINE_MIN_AGE="1800"
TIMELINE_LIMIT_HOURLY="24"
TIMELINE_LIMIT_DAILY="10"
TIMELINE_LIMIT_WEEKLY="3"
TIMELINE_LIMIT_MONTHLY="0"
TIMELINE_LIMIT_YEARLY="0"
# cleanup empty pre-post-pairs
EMPTY_PRE_POST_CLEANUP="yes"
# limits for empty pre-post-pair cleanup
EMPTY_PRE_POST_MIN_AGE="1800"
This configuration keeps one snapshot for each of the previous 24 hours, 10 days, and 3 weeks. I could retain snapshots for months and years, but for my desktop’s root filesystem this just isn’t unnecessary. Refer to Tuning Periodic Snapshotting from the Btrfs maintenance toolbox for good rules of thumb.
Now that the config is ready, enable it by adding it to the list of Snapper configs in /etc/sysconfig/snapper
.
SNAPPER_CONFIGS="root"
One of the features of Snapper is that users can manage snapshots within their home directory. This introduces a nice separation of concerns and responsibilities. A PAM module is also provided which can take snapshots whenever a user logs in and subsequently logs out.
In contrast to the previous configuration, the snapshots directory created for the user’s home directory follows a nested layout. This is much simpler.
Create a subvolume for snapshots in the user’s home directory.
sudo btrfs subvolume create ~/.snapshots
The |
The steps outlined here configure snapshots for a user’s home directory. This configuration assumes that the user’s home directory resides on a dedicated subvolume.
Create a Snapper configuration file for the user’s home directory.
sudo cp /etc/snapper/config-templates/default /etc/snapper/configs/home_jordan
Edit the template as necessary.
There are two important distinctions from the root filesystem configuration.
First, the ALLOW_USERS
parameter includes the name of the user.
This permits the user to work with the config.
Second, SYNC_ACL
is enabled, allowing the user to work with the snapshots in the ~.snapshots
directory.
# subvolume to snapshot
SUBVOLUME="/home/jordan"
# filesystem type
FSTYPE="btrfs"
# btrfs qgroup for space aware cleanup algorithms
QGROUP=""
# fraction of the filesystems space the snapshots may use
SPACE_LIMIT="0.5"
# fraction of the filesystems space that should be free
FREE_LIMIT="0.2"
# users and groups allowed to work with config
ALLOW_USERS="jordan"
ALLOW_GROUPS=""
# sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
# directory
SYNC_ACL="yes"
# start comparing pre- and post-snapshot in background after creating
# post-snapshot
BACKGROUND_COMPARISON="yes"
# run daily number cleanup
NUMBER_CLEANUP="yes"
# limit for number cleanup
NUMBER_MIN_AGE="1800"
NUMBER_LIMIT="50"
NUMBER_LIMIT_IMPORTANT="10"
# create hourly snapshots
TIMELINE_CREATE="yes"
# cleanup hourly snapshots after some time
TIMELINE_CLEANUP="yes"
# limits for timeline cleanup
TIMELINE_MIN_AGE="1800"
TIMELINE_LIMIT_HOURLY="48"
TIMELINE_LIMIT_DAILY="14"
TIMELINE_LIMIT_WEEKLY="8"
TIMELINE_LIMIT_MONTHLY="12"
TIMELINE_LIMIT_YEARLY="2"
# cleanup empty pre-post-pairs
EMPTY_PRE_POST_CLEANUP="yes"
# limits for empty pre-post-pair cleanup
EMPTY_PRE_POST_MIN_AGE="1800"
This configuration keeps one snapshot for each of the previous 48 hours, 14 days, 8 weeks, 12 months, and 2 years. This is quite extensive, but for preserving critical data in a user’s home directory it’s sensible.
Enable the home_jordan
Snapper config by adding to the SNAPPER_CONFIGS
list.
SNAPPER_CONFIGS="root home_jordan"
If you wish to take snapshots of a user’s home directory upon log in and log out, you’ll need to install the PAM module. The user’s home directory must be its own subvolume and must have an enabled Snapper config such as the one created previously. The steps necessary to install Snapper’s PAM module follow.
Install Snapper’s PAM module.
sudo apt -y install libpam-snapper
Add the pam_snapper.so
module to the PAM configuration for the session
type.
session optional pam_snapper.so ignoreroot cleanup=timeline
You will almost certainly want to set a cleanup algorithm as done here otherwise old snapshots won’t be deleted automatically. |
Snapper doesn’t provide a graphical user interface, but that doesn’t mean there isn’t one. Checkout the snapper-gui project if you’d like one!
This post has given a run down of managing Btrfs snapshots with Snapper. You should now be able to create Snapper configurations at both the system and user levels. Now you’ll probably want to backup those snapshots in case there’s a catastrophic failure or some such. Stay tuned for an upcoming tutorial on configuring backups plus more posts on getting the most out of Snapper!