When zfsonlinux became stable, I switched most of my linux /home filesystems from ext4 to zfs and I’m happy with that so far as performance, stability, and usability is concerned1.
So now I have efficient snapshotting thanks to CoW, compression, builtin RAID modes, and all the other nice features that zfs offers.
Goodbye mdadm and, more important, goodbye rsnapshot!

However, RAID and snapshotting are no backup. RAID is for redundancy and snapshots are basically versioning.
So the next step had to be backing up the zpool to a different drive.
For this matter, zfs provides zfs send and zfs recv, which let you replicate filesystems.

zfs send creates a stream representation of a snapshot, whereas zfs recv creates a snapshot from such stream.
To backup an entire zpool, the option -R is interesting, as it instructs zfs to send a replication stream that also includes descending filesystems, snapshots, and properties.

The following sections show how I do my backup - your use case might be different.
As zfs provides several options for these commands, make sure to have a look at the excellent manpage to see what fits best for you.

Initial backup

To initially backup my home filesystem into a backup zpool, I need a recent snapshot:
zfs snapshot -r home@$(date +%Y%m%d)
which provides a recursive snapshot, e.g., home@20180826.
Now I can create an initial backup of my home zpool using send/recv:
zfs send -R home@20180826 | zfs recv -Fu backup/home
While -F destroys existing filesystems and snapshots not present in the sent stream, -u ensures that the received filesystem is not mounted, which I don’t need/want on my backup pool.

Incremental backups

Now that I have a full clone of my home filesystem on my backup pool, I want to backup the deltas on the following day.
After creating the respective snapshot, e.g., home@20180827, I can make use of the -I option of zfs send:
zfs send -RI home@20180826 home@20180827 | zfs recv -Fu backup/home
Note that -I would also include any snapshots between the two specified snapshots, so if I make snapshots of home every day but want to trigger the backup only once a week, I still need to issue only one command to transfer all snapshots.


For my personal use case scenario, I automated the snapshotting and replicating process in a little script, which creates a new snapshot of home, finds the latest snapshot present in the backup pool, and transfers the new snapshot and all that are not yet in the backup.
Note that I receive the stream to $targetpool/$(hostname -s)/home, as I want to backup home filesystems from several machines, and the hostname layer helps me to manage them.
Usage is easy: dobackup [targetpool].

Replicating via SSH

Sometimes the target pool is not mounted locally but on a remote machine.
We can still backup using the same command set over ssh:
zfs send ... | ssh root@remote zfs recv ...

We don’t even need to login as root, as we can use a dedicated user account (let’s call it backupuser) instead after a little setup:
zfs allow backupuser atime,create,destroy,mount,mountpoint,receive,rollback,snapshot,userprop targetpool/targetfs

For a more secure setup, we can use ssh-keys for that dedicated user and configure the remote machine to allow only one specific command to be executed. This can be done on the remote machine by prefixing backupuser’s public key in his $HOME/.ssh/authorized_keys with a command argument:

command="/usr/sbin/zfs recv -Fu targetpool/targetfs" ssh-rsa ...

Note that this command is automatically executed when backupuser is logged in via ssh, so our new backup command is:
zfs send ... | ssh backupuser@remote

  1. In between I had a short experimentation phase with btrfs that did not make me so happy and is a topic for itself.