zfs send produce un stream replicable, no un directorio. El destino natural es otro pool (zfs recv). S3 es un segundo salto: guardas el stream como objeto, o usas una herramienta tipo z3.

Incremental a otro host (el comando que uso)

1
2
zfs send -w -R -v -i vol1/secure/backups@initial vol1/secure/backups@new \
  | ssh root@10.0.0.1 zfs recv -s vol1/secure/backups
FlagQué hace
-wraw: manda el dataset cifrado como está. El destino no necesita la key para recibir.
-Rreplica propiedades y snapshots hijas
-i @initial @newincremental desde @initial (tiene que existir en origen y destino)
-vprogreso
recv -sresumible si se corta el SSH (zfs restart / recv -s otra vez)

Pon un hold en @initial y @new mientras corre el send, o el prune te rompe la cadena.

El primer full (sin -i) es obligatorio una vez:

1
2
zfs send -w -R -v vol1/secure/backups@initial \
  | ssh root@10.0.0.1 zfs recv -s vol1/secure/backups

Aterrizar en S3

Mismo stream, otro lado del pipe:

1
2
3
zfs send -w -R vol1/secure/backups@new \
  | gzip -1 \
  | aws s3 cp - s3://mi-bucket/zfs/backups@new.zfs.gz

Restaurar:

1
2
3
aws s3 cp s3://mi-bucket/zfs/backups@new.zfs.gz - \
  | gunzip \
  | zfs recv -s vol1/secure/backups

Esto no es un sync de archivos. Es un blob opaco: o recuperas el stream entero (o el incremental encima del full), o no recuperas nada. Versiona los nombres @initial, @new y no borres el full.

Para incrementales en S3, herramientas como z3 llevan el catálogo de qué snapshot ya subió. Un aws s3 cp - crudo no sabe de eso.

-w en S3 es correcto si el dataset ya está cifrado: Amazon no ve plaintext. Si el origen no está cifrado, o cifras en recv (artículo) o cifras el objeto (KMS / cliente) — el stream en claro en un bucket es un backup en claro.

Ver también: cifrado nativo.