Contents (16 sections)
- Why ZFS for high availability
- Prerequisites
- Step 1: install ZFS if needed
- Step 2: create the ZFS pool
- Why ashift=12
- Compression: zstd rather than lz4
- Step 3: tune the ZFS ARC (RAM)
- Step 4: add the storage in Proxmox
- Step 5: migrate existing VMs
- Step 6: enable replication between nodes
- Monitoring and maintaining the pool
- Daily health check
- Automatic monthly scrub
- E-mail alerts on degradation
- Classic pitfalls to avoid
- Conclusion
The Proxmox templates supplied by OVH are installed on LVM by default. That makes them quick to provision, but it rules out replication between nodes, atomic snapshots and native data integrity. To unlock real high availability in Proxmox, you need to switch to ZFS: here is the full procedure, tested in production on a three-node OVH cluster.
Why ZFS for high availability #
ZFS supports native replication between nodes through zfs send/receive, the mechanism used by the Proxmox HA module. LVM does not. Other benefits: near-instant atomic snapshots, native compression (practically free in CPU terms in 2026 with zstd), and periodic integrity checks (scrubs) that catch silent corruption before it spreads into your backups.
The drawbacks you need to know about: ZFS needs RAM (allow at least 1 GB of ARC per TB of usable data), it cannot grow a pool as flexibly as LVM (adding a disk means a new vdev or a full replacement), and some unusual Linux operations (POSIX ACLs with chmod, NFS root) need specific settings.
Prerequisites #
- A Proxmox 8.x cluster with at least 2 nodes (on a single node, ZFS is still useful for snapshots and integrity).
- A disk dedicated to ZFS: a second physical disk, ideally NVMe on the OVH High Grade / Scale / Advance ranges. ZFS cannot share the same disk with LVM.
- Root SSH access on every node in the cluster.
- A full, tested backup BEFORE you start (PBS, LVM snapshot or
vzdumpexport depending on the context). - RAM: allow at least 8 GB on the host, of which about 4 GB is reserved for the ZFS ARC (cache). See step 3 for precise tuning.
Step 1: install ZFS if needed #
On recent OVH Proxmox templates, zfsutils-linux is already installed. On older images or on a manual Debian + Proxmox installation, you have to add it explicitly.
apt update && apt install -y zfsutils-linux
modprobe zfs
zfs versionThe zfs version command confirms that the kernel module is loaded. If it fails, it usually means the running kernel lacks the ZFS headers: reinstall pve-headers-$(uname -r) and reload the module.
Step 2: create the ZFS pool #
We create a ZFS storage pool named rpool (the Proxmox convention) on the dedicated disk, with two structural settings applied at creation time.
# First check you have the right target device
lsblk
parted -l
# Create the pool on the second disk
zpool create -o ashift=12 rpool /dev/sdb
# Enable compression and disable atime (performance)
zfs set compression=zstd rpool
zfs set atime=off rpool
# Create the dataset dedicated to VMs and CTs
zfs create rpool/dataWhy ashift=12 #
ashift=12 aligns ZFS blocks on 4 KB (2^12 bytes), the native size of modern SSDs and NVMe drives. Without this parameter, ZFS might align on 512 bytes, cutting write performance on flash disks by a factor of 4 to 8. The parameter is fixed when the pool is created and cannot be changed afterwards, which is why it matters so much to set it from the start.
Compression: zstd rather than lz4 #
The older Proxmox documentation recommended lz4. On 6.5+ kernels with ZFS 2.2+ (standard since Proxmox 8.1), zstd at its default level 3 gives a better compression ratio for barely more CPU, and remains faster than lz4 on reads thanks to multi-threading. Unless you have a specific reason (a very weak CPU, an extreme synchronous workload), go straight to zstd.

rpool/data dataset on a single vdev, with zstd compression and 4K alignment locked in at creation.Step 3: tune the ZFS ARC (RAM) #
By default, ZFS claims up to 50% of the host's total RAM for its ARC (Adaptive Replacement Cache). On an OVH server with 32 GB of RAM meant for 8 VMs, ZFS would take 16 GB at boot, leaving 16 GB for the VMs and the hypervisor itself. That is almost always too much, especially when the VMs have their own filesystem cache on the guest side.
A practical rule: set the ARC to 1 GB per TB of ZFS data actually in use, capped at 25% of the host's total RAM. With 32 GB of RAM, that gives 4 to 8 GB of ARC depending on the pool size.
# Cap the ARC at 4 GB (value in bytes: 4 * 1024^3)
echo 'options zfs zfs_arc_max=4294967296' > /etc/modprobe.d/zfs.conf
update-initramfs -u
systemctl reboot
# After the reboot, check the effective values
awk '/^c_max|^size/ {print $1, $3}' /proc/spl/kstat/zfs/arcstatsStep 4: add the storage in Proxmox #
In the web interface: Datacenter → Storage → Add → ZFS. Select the rpool/data pool, give it a readable ID (e.g. local-zfs), and tick Thin provision to save space. Do NOT tick Shared unless you have a pool that is synchronous across nodes (a rare case, such as Ceph on top of ZFS). For standard asynchronous Proxmox replication, leave this box unticked.
Step 5: migrate existing VMs #
Assumption: the OVH template created a local-lvm storage on LVM that currently hosts your VMs. The commands below move a VM (VMID 100) from LVM to the new ZFS pool, live or offline depending on the situation.
# Identify the current disks of VM 100
qm config 100 | grep -E '^(scsi|virtio|sata|ide)[0-9]'
# Online migration (VM running, copy without downtime ~ 1 to 3 GB/min)
qm move-disk 100 scsi0 local-zfs --delete
# Offline migration (VM shut down, much faster)
qm shutdown 100 && qm move-disk 100 scsi0 local-zfs --delete && qm start 100Step 6: enable replication between nodes #
Once the VM is on ZFS, replication becomes trivial. In the web interface, open the VM → Replication → Add → choose the target node and the frequency (cron in Proxmox format: */15 = every 15 minutes, 0 */6 = every 6 hours on the hour).
Check in the logs (/var/log/pve/replicate-*) that the first replication succeeds. The first synchronisation transfers the whole dataset; later ones only push the changed blocks (a zfs send -i delta), typically 50 to 500 MB per cycle on a moderately active VM.

Monitoring and maintaining the pool #
A ZFS pool without monitoring is a silent trap: a corrupted disk can stay invisible for weeks before showing up in a replication or a backup, by which point it is too late to recover because the backups already contain the corrupted blocks.
Daily health check #
# Pool and disk status, and corruption detection
zpool status -v rpool
# All is well if the output shows:
# state: ONLINE
# errors: No known data errorsAutomatic monthly scrub #
A scrub reads the entire pool and compares checksums: it is the only way to detect silent corruption (bit rot) before it spreads. Proxmox 8 ships a systemd timer, zfs-scrub-monthly@rpool.timer: check that it is enabled.
# Enable the automatic monthly scrub on the rpool pool
systemctl enable --now zfs-scrub-monthly@rpool.timer
# Run a manual scrub on demand (takes several hours on a large pool)
zpool scrub rpool
# Follow the progress
zpool status rpoolE-mail alerts on degradation #
The pool can go into a DEGRADED state (one failed disk in a mirror) or FAULTED (redundancy lost, data potentially inaccessible) without anyone noticing. Configure the zed daemon (ZFS Event Daemon) to send an e-mail on every critical state change.
# Configure zed with the e-mail address that receives the alerts
sed -i 's|^#ZED_EMAIL_ADDR=.*|ZED_EMAIL_ADDR="admin@exemple.fr"|' /etc/zfs/zed.d/zed.rc
sed -i 's|^#ZED_NOTIFY_INTERVAL_SECS=.*|ZED_NOTIFY_INTERVAL_SECS=3600|' /etc/zfs/zed.d/zed.rc
systemctl restart zfs-zed
# Test by listing events (without breaking the pool)
zpool events rpoolClassic pitfalls to avoid #
- ashift too low: pool created without
ashift=12on SSD/NVMe. Write performance divided by 4 to 8, impossible to fix without recreating the pool. - ARC eating the RAM: without
zfs_arc_max, the ARC can stop VMs from starting for lack of available RAM. Symptom: VMs OOM-killed with no application cause. - Disk added without planning:
zpool addadds a new vdev (it widens the pool). If the added disk is not mirrored, the failure of that single disk destroys the entire pool. Always replicate the topology of the existing vdev. - No scrubs: without scrubs, silent corruption is only detected when you restore a backup… which by then also contains the corrupted blocks.
- Replication without monitoring: replication can fail silently (network, space on the target disk, diverging datasets). Watch
/var/log/pve/replicate-*.logand alert on errors.
Conclusion #
Converting an OVH template from LVM to ZFS unlocks three features that make Proxmox's high-availability promise genuinely usable: replication between nodes, atomic snapshots and periodic integrity checks. The initial effort (1 to 2 hours per node) pays for itself the first time a disk failure is avoided, or the first time a scrub catches silent corruption before it contaminates the backups.
To go further with the backup strategy that complements ZFS replication, the PBS guide covers source-side deduplication, multi-level retention and ransomware protection. And to reproduce this setup on a Hetzner server rather than OVH, the guide to installing Proxmox 8 on Hetzner leads naturally into this one.




