Set Up Encrypted ZFS on Ubuntu 24.04 with Automatic Snapshots and Replication (Sanoid + Syncoid)

ZFS combines a robust filesystem with volume management, snapshots, and replication in one toolset. In this guide, you will deploy ZFS on Ubuntu 24.04, create an encrypted dataset, and set up automatic snapshots and offsite replication using Sanoid and Syncoid. The steps are safe for production, SEO-friendly, and easy to follow for sysadmins and power users.

What you will achieve: install ZFS, create a tuned pool, enable native encryption, configure automatic snapshots (Sanoid), and push incremental backups to another host (Syncoid). You will also learn a few health and troubleshooting commands to keep your pool in good shape.

Prerequisites

- Ubuntu 24.04 (server or desktop).
- Two or more blank disks (recommended) or one disk for testing. Use /dev/disk/by-id/... paths for stable device names.
- Root or sudo privileges on both the source and the backup host (for replication).
- SSH connectivity to a backup host if you plan to use Syncoid.

Install ZFS and useful tools

Run the following commands to install ZFS and snapshot/replication tools:

sudo apt update && sudo apt install -y zfsutils-linux sanoid mbuffer openssh-client openssh-server

Confirm the kernel module is loaded:

sudo modprobe zfs && zpool --version

Create a ZFS pool with sensible defaults

List disks by ID so device names don't change across reboots:

ls -l /dev/disk/by-id/

Example: create a mirrored pool named tank using two drives. The options below enable modern defaults like zstd compression and a 4K-friendly sector size:

sudo zpool create -o ashift=12 -O compression=zstd -O atime=off -O xattr=sa -O mountpoint=/tank tank mirror \
/dev/disk/by-id/ssd-a-id /dev/disk/by-id/ssd-b-id

If you have a single disk for testing, omit the mirror keyword. Enable periodic trim for SSDs:

sudo zpool set autotrim=on tank

Create a native encrypted dataset

ZFS native encryption protects data at rest at the dataset level. The command below creates an encrypted dataset and prompts for a passphrase:

sudo zfs create -o encryption=on -o keyformat=passphrase -o keylocation=prompt -o compression=zstd tank/secure

Mount paths are created automatically under /tank. To unlock an encrypted dataset after a reboot, use:

sudo zfs load-key tank/secure && sudo zfs mount -a

Optional (auto-unlock on headless servers): store a key file with strict permissions. Understand the risk—this trades convenience for reduced physical security.

sudo mkdir -p /etc/zfs/keys && sudo chmod 700 /etc/zfs/keys
echo "YOUR-LONG-PASSPHRASE" | sudo tee /etc/zfs/keys/secure.key > /dev/null
sudo chmod 600 /etc/zfs/keys/secure.key
sudo zfs set keylocation=file:///etc/zfs/keys/secure.key tank/secure

Install and configure Sanoid for automatic snapshots

Sanoid provides policy-driven snapshots and pruning. Create a configuration:

sudo nano /etc/sanoid/sanoid.conf

Use this minimal but production-ready policy (adjust to your needs):

[template_production]
hourly = 24
daily = 7
weekly = 4
monthly = 12
autosnap = yes
autoprune = yes

[tank/secure]
use_template = production
recursive = yes

Enable the systemd timer so snapshots run hourly by default:

sudo systemctl enable --now sanoid.timer

You can trigger an immediate run and inspect logs:

sudo systemctl start sanoid.service
journalctl -u sanoid.service --no-pager

Set up Syncoid for incremental replication

Install ZFS and Sanoid/Syncoid on the backup host as well. Then configure key-based SSH so the source can reach the backup host:

sudo -i
ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N ""
ssh-copy-id -i /root/.ssh/id_ed25519.pub backup@backup-host

Run an initial replication. Syncoid will create the destination dataset if needed and then send incremental diffs after the first run:

syncoid --recursive tank/secure backup@backup-host:tankbackup/secure

Automate replication on a schedule using systemd. Create a service:

sudo nano /etc/systemd/system/syncoid-secure.service

[Unit]
Description=Replicate tank/secure to backup host
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/sbin/syncoid --recursive tank/secure backup@backup-host:tankbackup/secure

Create an hourly timer:

sudo nano /etc/systemd/system/syncoid-secure.timer

[Unit]
Description=Hourly Syncoid for tank/secure

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target

Enable it:

sudo systemctl daemon-reload
sudo systemctl enable --now syncoid-secure.timer
systemctl list-timers | grep syncoid

Health checks and maintenance

- Check pool state: zpool status -v
- List datasets and snapshots: zfs list and zfs list -t snapshot
- Start a monthly scrub (data integrity check) via cron: sudo crontab -e and add 0 3 1 * * zpool scrub tank
- Monitor free space: keep pools under ~80% to maintain performance.

Troubleshooting

- Pool not importing after reboot: sudo zpool import then sudo zpool import -f tank if needed.
- Encrypted dataset locked: sudo zfs load-key tank/secure then sudo zfs mount -a.
- Replication permission errors: ensure the remote user can run ZFS commands (use root over SSH or configure sudoers for /sbin/zfs and /sbin/zpool without password).
- Disk IDs changed: always use /dev/disk/by-id/ when creating pools.

You now have a modern, encrypted ZFS setup on Ubuntu 24.04 with automatic snapshots and scheduled replication. This design gives you fast local rollbacks, versioned backups, and an offsite copy—meeting the core pillars of data protection with minimal moving parts.

Comments