Self-validating backup and disaster recovery appliance built with Syncthing, ZFS, Sanoid, Restic, and Ubuntu. SyncVault implements a practical 3-2-1-1-0 backup strategy as infrastructure-as-code.
- Automated Ubuntu deployment
- Native ZFS storage
- Sanoid snapshot automation
- Syncthing replication
- Restic local and offsite backups
- Backblaze B2 support
- Immutable backup workflows
- Automated restore testing
- Continuous validation
- Hardened network security
- Infrastructure-as-code deployment
SyncVault is designed around the modern 3-2-1-1-0 backup rule:
| Requirement | SyncVault Implementation |
|---|---|
| 3 copies of data | live data + local Restic + optional B2 |
| 2 storage/media types | ZFS + Restic repositories |
| 1 offsite copy | Backblaze B2 |
| 1 immutable/offline copy | B2 Object Lock |
| 0 unverified backups | automated restore validation |
SyncVault is a reproducible infrastructure-as-code backup VM that combines:
- Syncthing replication
- Sanoid-curated ZFS snapshots
- Restic backups
- Backblaze B2 offsite recovery
- automated restore testing
- hardened Ubuntu deployment
- continuous validation and integrity checks
into a single deployable system that can create a fully functional QEMU virtual machine in just a few minutes.
I originally built SyncVault because I wanted a dependable, decentralized way to curate and preserve my phone user data.
Syncthing already solved real-time synchronization beautifully, but combining it with ZFS datasets and Sanoid snapshots created a much stronger foundation for recovery and versioned storage.
Adding Restic enabled encrypted local and offsite backups, while scripted validation and restore testing made it possible to continuously verify the entire recovery chain.
The result became a practical implementation of the 3-2-1-1-0 backup strategy delivered as infrastructure-as-code.
This guide explains how to build, deploy, boot, and validate the SyncVault backup appliance.
Recommended host environment:
- Linux host
- QEMU/KVM
- 2+ CPU cores
- 4 GB RAM minimum
- 64+ GB storage
Install:
sudo apt update
sudo apt install \
qemu-system-x86 \
qemu-utils \
ovmf \
cloud-image-utils \
python3Download Ubuntu Server 24.04 LTS into project directory. In your project directory:
wget https://releases.ubuntu.com/24.04/ubuntu-24.04.3-live-server-amd64.iso
After downloading the Ubuntu iso your project directory should at least contain the following:
syncvault/
├── user-data
├── meta-data
└── ubuntu-24.04.3-live-server-amd64.iso
Edit:
user-data
Replace placeholders:
CHANGE_ME_PASSWORD_HASH
CHANGE_ME_SSH_PUBLIC_KEY
CHANGE_ME_RESTIC_PASSWORD
CHANGE_ME_B2_BUCKET
CHANGE_ME_RESTIC_PASSWORD
CHANGE_ME_B2_ACCOUNT_ID
CHANGE_ME_B2_ACCOUNT_KEY
Note: You can/should change the username and hostname.
Generate SHA-512 password hash:
mkpasswd --method=SHA-512Paste result into:
identity:
password: "YOUR_HASH"Insert your SSH public key into:
ssh:
authorized-keys:
- "ssh-ed25519 AAAA..."From the repository directory:
python3 -m http.server 8000This serves:
user-datameta-data
to cloud-init.
Example:
qemu-img create -f qcow2 syncvault.qcow2 64Gcp /usr/share/OVMF/OVMF_VARS_4M.fd .
Example QEMU launch:
qemu-system-x86_64 \
-enable-kvm \
-m 4096 \
-smp 2 \
-cpu host \
-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd \
-drive if=pflash,format=raw,file=OVMF_VARS.fd \
-drive file=syncvault.qcow2,format=qcow2 \
-cdrom ubuntu-24.04.3-live-server-amd64.iso \
-net nic \
-net user,hostfwd=tcp::2222-:22At the GRUB menu:
Press:
e
Find the Linux kernel line and append:
autoinstall 'ds=nocloud-net;s=http://10.0.2.2:8000/'
Final line example:
linux /casper/vmlinuz autoinstall 'ds=nocloud-net;s=http://10.0.2.2:8000/' ---
Then boot with:
Ctrl+x
The appliance will automatically:
- install Ubuntu
- configure ZFS
- configure Syncthing
- configure Restic
- configure Sanoid
- configure UFW
- configure Fail2ban
- configure validation tooling
- configure maintenance timers
Installation typically completes within several minutes.
SSH into the VM:
ssh -p 2222 USER@127.0.0.1On the VM, check installation completion:
sudo systemctl status cloud-final.serviceExpected:
Active: active (exited)
Then:
cloud-init statusExpected:
status: done
or:
status: disabled
Both are acceptable after successful provisioning.
On the VM, run:
sudo validate-syncvault-healthChecks include:
- ZFS health
- timers
- snapshot freshness
- repository metadata
- security posture
- capacity thresholds
Expected:
SYNCVAULT HEALTH VALIDATION PASSED
On the VM, run full disaster recovery validation:
sudo validate-syncvault-deepThis performs:
- snapshot creation
- local Restic backup
- restore testing
- repository integrity verification
Expected:
SYNCVAULT ALL VALIDATION PASSED
On the VM, view validation timers:
systemctl list-timers 'validate-syncvault-*'View scrub timers:
systemctl list-timers 'zfs-scrub-*'Expected timers:
validate-syncvault-health.timer
validate-syncvault-all.timer
zfs-scrub-rpool.timer
zfs-scrub-bpool.timer
On the VM, check service:
systemctl status syncthing@YOUR_USERVerify GUI is localhost-only:
ss -lntp | grep 8384Expected:
127.0.0.1:8384
On the host, create SSH tunnel:
ssh -L 8386:127.0.0.1:8384 -p 2222 USER@127.0.0.1Then on the host, open:
http://127.0.0.1:8386
On the VM, edit:
/etc/restic/b2.env
Example:
export RESTIC_REPOSITORY=b2:YOUR_BUCKET:backup01
export RESTIC_PASSWORD=CHANGE_ME_RESTIC_PASSWORD
export B2_ACCOUNT_ID=CHANGE_ME_B2_ACCOUNT_ID
export B2_ACCOUNT_KEY=CHANGE_ME_B2_ACCOUNT_KEYOn the VM, run:
sudo enable-restic-b2On the VM, fast validation:
sudo validate-restic-b2Full restore drill:
sudo validate-restic-b2-fullSyncVault is designed around continuous operational validation.
The appliance continuously verifies:
- backup creation
- restore capability
- repository integrity
- snapshot freshness
- ZFS health
- scrub scheduling
- security posture
The goal is not simply to create backups, but to continuously verify recoverability.
After deployment:
- connect Syncthing peers
- configure backup retention policies
- configure Backblaze B2
- perform restore drills
- monitor validation timers
- commit infrastructure changes to Git
On the VM,
zpool status
zfs listOn the VM,
sudo sanoid --take-snapshotsOn the VM,
sudo sh -c '. /etc/restic/local.env && restic snapshots'On the VM,
systemctl list-timersMIT License
---