TL;DR
zfs send -w -R -i over SSH to zfs recv -s. The stream is not a tarball; S3 is an extra hop if needed.
zfs send emits a replicable stream, not a directory. The natural sink is another pool (zfs recv). S3 is a second hop: store the stream as an object, or use something like z3.
Incremental to another host (the command I actually run)
| |
| Flag | Meaning |
|---|---|
-w | raw: send the dataset encrypted as-is. The receiver does not need the key to recv. |
-R | replicate properties and child snapshots |
-i @initial @new | incremental from @initial (must exist on both sides) |
-v | progress |
recv -s | resumable if SSH drops (recv -s again) |
Hold @initial and @new while the send runs, or prune will break the chain.
The first full (no -i) is mandatory once:
| |
Land it in S3
Same stream, other side of the pipe:
| |
Restore:
| |
This is not a file sync. It is an opaque blob: you restore the whole stream (or the incremental on top of the full), or you restore nothing. Name @initial / @new and do not delete the full.
For incrementals in S3, tools like z3 keep a catalog of what already landed. A raw aws s3 cp - does not.
-w into S3 is correct if the dataset is already encrypted: AWS never sees plaintext. If the source is not encrypted, either encrypt on recv (post) or encrypt the object (KMS / client) — a cleartext stream in a bucket is a cleartext backup.
See also: native encryption.