If you run Proxmox on ZFS, you already have one of the best filesystems for virtualization. But running zfs snapshot by hand or relying solely on Proxmox’s vzdump scheduler leaves gaps — manual effort, full-dump overhead, or recovery points that are too far apart.
ZFS snapshot replication fills those gaps. Snapshots are instant (copy-on-write), near-free in disk space (only changed blocks consume space), and incremental sends make off-site or secondary-host replication practical even over slow links.
This guide covers the full stack: sanoid for automated snapshot creation and retention, syncoid for push replication to a backup host, and systemd timers to tie it together. By the end, you’ll have fully automated, versioned VM/CT backups replicated to a second Proxmox host or NAS without vzdump touching a single disk.
ZFS Snapshot Primer for Proxmox Backups
Before we automate, understand what ZFS snapshots are good for in Proxmox. When you create a VM on a ZFS pool, Proxmox creates a ZFS volume (zvol) named tank/vm-100-disk-0. You can snapshot that zvol instantly — it takes milliseconds regardless of size:
|
|
List snapshots:
|
|
Key differences from vzdump:
| Aspect | vzdump | ZFS snapshot |
|---|---|---|
| Speed | Minutes to hours (full VM read/write) | Milliseconds (CoW metadata) |
| Space | Full VM size per backup | Only changed blocks since last snapshot |
| Granularity | Bloated or compressed archive | Per-dataset, per-VM, per-CT |
| Restore | Full VM restore only | Rollback or clone individual disks |
Snapshots don’t replace vzdump for full-system restores to bare metal — but for rapid recovery, rollback after a bad update, or incremental off-site replication, nothing beats ZFS snapshots.
Installing and Configuring Sanoid
Sanoid is the de-facto standard for ZFS snapshot lifecycle management. It creates snapshots on schedule and prunes old ones based on retention policies you define. Install it on your primary Proxmox host:
|
|
Create /etc/sanoid/sanoid.conf with your dataset policies:
|
|
Test the configuration:
|
|
Set up a systemd timer to run sanoid every 15 minutes. Create /etc/systemd/system/sanoid.timer:
|
|
And /etc/systemd/system/sanoid.service:
|
|
Enable and start:
|
|
Setting Up Syncoid for Replication
Sanoid handles snapshots locally. Syncoid pushes them to a remote host over SSH.
SSH Key Authentication
Generate a dedicated SSH key on the primary host for the replication user:
|
|
Test the connection:
|
|
Basic One-Shot Replication
Push your VM zvol snapshots to the backup host:
|
|
Flags explained:
--recursive: replicate all child datasets--no-sync-snap: create temporary sync snapshots during transfer--compress=lz4: compress the stream (add this for WAN links)
Syncoid automatically detects which snapshots the target already has and sends only the incremental difference. The first run sends everything; subsequent runs are near-instant.
Bandwidth Limited Replication
For WAN replication over slower links:
|
|
The --bwlimit flag passes through to pv or mbuffer internally, throttling the transfer to 10 MB/s.
Full Automation Script
Tie sanoid and syncoid together in a single script that runs on a schedule, handles errors, and notifies you on failure.
Create /usr/local/bin/zfs-backup.sh:
|
|
Make it executable and test:
|
|
Systemd Timer for Daily Replication
Create /etc/systemd/system/zfs-replication.service:
|
|
And /etc/systemd/system/zfs-replication.timer:
|
|
Enable it:
|
|
Disaster Recovery
When a VM fails and you need to restore from your replicated snapshots, you have several paths.
Option A: Restore via Syncoid Reverse
Pull the snapshot back from the backup host:
|
|
Option B: Manual zfs send/recv
List available snapshots on the backup host:
|
|
The -F flag forces a rollback of the target to match the received snapshot. Use with care — it discards data on the target that is newer than the received snapshot.
Option C: Emergency VM Restore from Replicated Dataset
If Proxmox itself is inaccessible but the backup host has the replicated zvols:
- On the backup host, clone the snapshot to a temporary zvol
- Attach that zvol to a recovery VM (or raw qemu)
|
|
Validate Restorability
Periodically verify your snapshots are actually usable:
|
|
Conduct a quarterly restore test: bring up a temporary VM from a replicated snapshot and confirm the data is intact.
Monitoring and Maintenance
Keep an eye on the replication pipeline with these checks:
|
|
Schedule ZFS scrubs to catch silent data corruption early:
|
|
And verify the remote pool is scrubbing too:
|
|
Conclusion
ZFS snapshot replication with sanoid and syncoid transforms VM backup from a manual chore into a hands-off, reliable process. Snapshots are instant, incremental sends are bandwidth-efficient, and the retention policies ensure you never accidentally keep snapshots forever nor delete them too soon.
In my homelab, this setup runs on two Proxmox hosts — one primary with a 4x NVMe ZFS mirror pool, and a secondary with spinning disks for backup. The daily replication completes in under 5 minutes for a dozen VMs. For the three times I’ve needed to roll back a VM after a bad apt upgrade or a misconfigured container, having hourly snapshots on both hosts saved hours of rebuild time.
If you run Proxmox on ZFS, there’s no excuse not to automate this. Install sanoid, configure your retention, point syncoid at a backup host, and let systemd handle the rest.