Remote Backup of Snapper Snapshots without Root SSH Login

Arvin Schnell, 28 April 2025

Recently the program snbk was added to snapper for easy and efficient creation of backups of the snapper snapshots using the btrfs send/receive mechanism. The backups can be placed on local or remote file systems. Since the btrfs send/receive mechanism requires root permissions so far it was required to allow ssh root login on the remote backup server. By using sudo from a wrapper script this root ssh login can be avoided.

Here we provide a step-by-step guide for a viable setup.

First we prepare the local system. All commands need to be run as root.

Install snapper-backup and enable the snapper-backup.timer unit:

# zypper in snapper-backup
[...]
# systemctl enable --now snapper-backup.timer
[...]

Verify that you have snapper 0.12.2 or later. Create a certificate for ssh, copy the private key to “/etc/snapper/certs/” and the public key to the backup server:

# ssh-keygen -t ecdsa -N '' -f .ssh/sesame
[...]
# cp .ssh/sesame /etc/snapper/certs/
# scp .ssh/sesame.pub linux@vault.local:/tmp/
[...]

Create the config for snbk as /etc/snapper/backup-configs/root-ssh.json:

{
    "config": "root",
    "target-mode": "ssh-push",
    "automatic": true,
    "source-path": "/",
    "target-path": "/backup/root",
    "ssh-host": "vault.local",
    "ssh-user": "backup",
    "ssh-identity": "/etc/snapper/certs/sesame",
    "target-btrfs-bin": "/usr/local/libexec/snbk/btrfs",
}

Second we prepare the remote backup server. Again all commands need to be run as root. There is no need to install snapper or snbk here.

Create a user “backup” with ssh login via the previously created certificate:

# useradd backup
# su - backup -c "mkdir .ssh"
# su - backup -c "cat /tmp/sesame.pub >> .ssh/authorized_keys"

A password for the backup user is not required. In any case ensure you can access the backup server somehow as root.

Create a btrfs file system for the backups mounted at “/backup”. We also create a directory “/backup/root” for the actual snapshots. This allows us to add backups from other subvolumes later.

# barrel create btrfs /dev/sdb --size 100g --path /backup
[...]
# mkdir /backup/root
# chown backup /backup/root

Using visudo we allow the user backup to execute some btrfs commands by add these four lines:

backup ALL=(ALL) NOPASSWD: /usr/sbin/btrfs subvolume list *
backup ALL=(ALL) NOPASSWD: /usr/sbin/btrfs subvolume show *
backup ALL=(ALL) NOPASSWD: /usr/sbin/btrfs subvolume delete *
backup ALL=(ALL) NOPASSWD: /usr/sbin/btrfs receive *

As already mentioned we add a wrapper script that is called by snbk via ssh. In that script we can additionally check that the btrfs commands act on the /backup path. The snapper repository includes an example for such a script:

# wget https://raw.githubusercontent.com/openSUSE/snapper/refs/heads/master/scripts/snbk-btrfs
[...]
# mkdir /usr/local/libexec/snbk/
# mv snbk-btrfs /usr/local/libexec/snbk/btrfs
# chmod a+x /usr/local/libexec/snbk/btrfs

The script should not be writable by the backup user.

We are now ready to check the setup. First we transfer the snapshots to the backup server (commands run on local system):

# snbk --verbose transfer
Running transfer for backup config 'root-ssh'.
Probing source snapshots.
Probing extra information for source snapshots.
Probing target snapshots.
Probing extra information for target snapshots.
Transferring snapshot 2.
Transferring snapshot 3.
Transferring snapshot 4.
Transferring snapshot 5.
Transferring snapshot 6.

Finally we verify the backup by listing the snapshots:

# snbk ls
# │ Date                     │ Source State │ Target State
──┼──────────────────────────┼──────────────┼─────────────
1 │ Mon Apr 28 07:09:39 2025 │ read-write   │
2 │ Mon Apr 28 07:18:14 2025 │ read-only    │ valid
3 │ Mon Apr 28 08:20:06 2025 │ read-only    │ valid
4 │ Mon Apr 28 08:20:08 2025 │ read-only    │ valid
5 │ Mon Apr 28 08:20:17 2025 │ read-only    │ valid
6 │ Mon Apr 28 08:21:24 2025 │ read-only    │ valid

The backups look fine. They will be transferred automatically every hour. As always with backups you have to check them regularly.

This setup is supported since snapper 0.12.2.