Simple ZFS Backup Script

ZFS is a powerful filesystem that helps to maintain integrity by avoiding data corruption. A useful feature of ZFS is its ability to clone filesystems. Creating snapshots allows for filesystems to be cloned and restored if anything happens to the original data. Going beyond this is the ability to maintain incremental changes between snapshots. There are a number of scripts available that setup a similar backup system, but the idea here is to maintain a current dataset, with the ability to restore from two previous backups.

The first step is to setup a backup system, or backup drive to use for the ZFS snapshots. In this setup, there is a separate remote FreeBSD system where the snapshots will be stored. This remote system has an encrypted ZFS filesystem (AES XTS with geli on boot), which provides a secure backup of the data. The root account on the local system is setup with an SSH key and this is deployed to the remote system:

# ssh-copy-id root@remote

Note: ssh-copy-id is available by default in FreeBSD 10. For older versions of FreeBSD, the port can be installed from /usr/ports/security/ssh-copy-id Now the root account can run the script without a password over a secure connection. If you do not wish to use the root account, the steps here can be applied to another user account on the remote system with permissions to perform ZFS operations. See the ZFS man page for more details about permissions. In this test steup, the remote machine has the same size hard disk as the local system. The first operation is to snapshot the filesystem and use zfs send to replicate the snapshot over to the remote system.

# zfs snapshot -r tank/usr/home@today
# zfs send -R tank/usr/home@today | ssh zfs recv -F zroot/homeback

Once the snapshot has been sent over to the remote system (this can take some time), validate that the snapshot is available on the remote system.

# zfs list -t snapshot
zroot/homeback@today 49.3M - 155G -

Now there is a snapshot of the home filesystem on the local system, and the remote system. Any changes made after the snapshot is created are recorded by ZFS. This is why snapshots though useful must be carefully managed as they can grow to be quite large. From the zfs man page “As data within the active dataset changes, the snapshot consumes more data than would otherwise be shared with the active dataset.”

# zfs list -t snapshot
tank/usr/home@today 102.2M - 155G -

A way to work with changes to the active dataset is to create incremental snapshots. This is a feature in ZFS that allows for the differences between snapshots to be stored. In this test setup, the incremental differences are sent to the remote system after creating a new snapshot. The first step is to rename the last snapshot (today) to yesterday. (For the script, it destroys the yesterday snapshot if it exists on both systems.)

# ssh zfs destroy zroot/homeback@yesterday
# zfs destroy tank/usr/home@yesterday
# zfs rename -r tank/usr/home@today @yesterday
# ssh zfs rename -r zroot/homeback@today @yesterday

Now a snapshot is taken of the home filesystem for today and the incremental snapshot is sent to the remote system.

# zfs snapshot -r tank/usr/home@today
# zfs send -R -i tank/usr/home@yesterady tank/usr/home@today | ssh zfs recv -F zroot/homeback

Now snapshots are available for the data on the local system, and if anything happens to the local system, the remote system has the ability to recover the data, or rebuild the home dataset on the local system. There is a great example of how to extend this daily operation to store snapshots over the course of seven days. This is Example 15 from the ZFS man page.

The following example shows how to maintain a history of snapshots with a consistent naming scheme. To keep a week's worth of snapshots, the user destroys the oldest snapshot, renames the remaining snapshots, and then creates a new snapshot, as follows:
# zfs destroy -r pool/users@7daysago
# zfs rename -r pool/users@6daysago @7daysago
# zfs rename -r pool/users@5daysago @6daysago
# zfs rename -r pool/users@4daysago @5daysago
# zfs rename -r pool/users@3daysago @4daysago
# zfs rename -r pool/users@2daysago @3daysago
# zfs rename -r pool/users@yesterday @2daysago
# zfs rename -r pool/users@today @yesterday
# zfs snapshot -r pool/users@today

The simple script is available on github: Once the variables are set for the local/remote systems (including the local and remote datasets), a cron job can be setup to run a backup daily, or weekly to maintain snapshots.

Copyright © 2023 Daemon Security Inc. | Privacy Policy
Terms and Conditions