My small home server runs on a distribution featuring ZFS. On that system, I implemented a rolling snapshot scheme:

  • every hour, a snapshot is created
  • once a day, the chain is thinned so that I have a set of hourly / daily / weekly / monthly snapshots

I would like to store an offsite backup of some of the file systems on a USB drive in my office. The plan is to update the drive every other week. However, due to the rolling snapshot scheme, I have troubles implementing incremental snapshots.

To given you an illustration, this is my desired procedure:

  1. Initial snapshot: zfs snap tank/fs@snap0
  2. Transfer initial snapshot: zfs send tank/fs@snap0 | zfs recv -Fduv backup_tank
  3. Store backup_tank offsite
  4. Make a few snapshots: zfs snap tank/fs@snap1, zfs snap tank/fs@snap2
  5. Thin the chain: zfs destroy tank/fs@snap0
  6. Return backup_tank and make an incremental update of the filesystem
  7. Obviously, zfs send -I snap0 tank/fs@snap2 | zfs recv -Fduv backup_tank fails as snap0 does not exist on tank anymore.

Long story cut short:

Is there a clever solution for combining thinning of snapshot chains and incremental send / recv? Every time I attach the drive and run some commands I would like to a have a copy of the file system at that point of time. In this example, backup_tankshould contain the snapshots fs@snap1 and fs@snap2.


3 Answers 3


You can't do exactly what you want.

Whenever you create a zfs send stream, that stream is created as the delta between two snapshots. (That's the only way to do it as ZFS is currently implemented.) In order to apply that stream to a different dataset, the target dataset must contain the starting snapshot of the stream; if it doesn't, there is no common point of reference for the two. When you destroy the @snap0 snapshot on the source dataset, you create a situation that is impossible for ZFS to reconcile.

The way to do what you are asking is to keep one snapshot in common between both datasets at all times, and use that common snapshot as the starting point for the next send stream.

So, you might in step 1 create a snapshot @backup0, and then some time around step 6 create and use a snapshot @backup1 to use for updating the off-site backup. You then transfer the stream that is the delta between @backup0 and @backup1 (which will include all intermediate snapshots), then delete @backup0 but keep @backup1 (which becomes the new common denominator). Next time you refresh the backup, you might create @backup2 (instead of @backup1) and transfer the delta between @backup1 and @backup2 (instead of @backup0 and @backup1) followed by deleting @backup1 (instead of @backup0), and so on.

  • can you plesae add an example of the commands involved, to demonstrate your idea? I am faced with this situation, and want to keep the source snapshots cleaned off, but its the system that im using a weekly zfs snapshot of a rsnapshot folder in. i want as much data moved to the offsite ZFS pool. Feb 4, 2023 at 21:25

Snapshots have arbitrary names. And zfs send -i [snapshot1] [snapshot2] can send the difference between any two snapshots. You can make use of that to have two (or more) sets of snapshots with different retention policies.

e.g. have one set of snapshots with names like @snap.$timestamp (where $timestamp is whatever date/time format works for you (time_t is easiest to do calculations with, but not exactly easy to read for humans. @snap.%s.%Y%M%D%H%M%S provides both). Your hourly/daily/weekly/monthly snapshot deletion code should ignore all snapshots that don't begin with @snap.

The second set, you can call @offsite.$timestamp. It should have whatever snapshot retention/deletion policy makes sense for that task, and the code used to manage it should ignore all snapshots that don't begin with @offsite.

BTW, this may be spelling out the obvious, but you can use this for your hourly, daily, weekly, monthly snapshots, so each can have different retention policies. e.g. @hourly.$timestamp, @daily.$timestamp etc instead of just @snap.$timestamp.

Also obviously, this will use more disk space because blocks used by datasets are not freed up until there are NO snapshots left that reference them.


You can use my zfs-auto-snapshot which is fork of original zfs-auto-snapshot updated with send2remote script

send2remote scans source and destination for difference is snapshots and send to backup zpool incremental snapshots via ssh(if backup zpool on remote host)

backup zpool - can be on local host or remote

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .