ZFS (Zettabyte File System) delivers enterprise-grade data integrity features including checksumming, copy-on-write snapshots, built-in RAID, and efficient replication — without requiring a separate volume manager. Although ZFS is not included in RHEL 9’s default kernel, the OpenZFS project provides DKMS-based packages that work reliably on RHEL 9. This tutorial covers installing OpenZFS, creating pools and datasets, taking snapshots, and replicating data to a remote host.

Prerequisites

  • RHEL 9 server with root or sudo access
  • EPEL 9 repository enabled (dnf install -y epel-release)
  • At least one additional block device (e.g., /dev/sdb) for the pool
  • Kernel development headers installed (dnf install -y kernel-devel)
  • SSH access to a second RHEL 9 host for the replication step (optional)

Step 1 — Install OpenZFS

OpenZFS is distributed via its own DNF repository. Install the repo RPM first, then install the zfs package. DKMS will compile the kernel module against your current kernel headers.

# Install the OpenZFS repository for RHEL 9 / EL9
sudo dnf install -y https://zfsonlinux.org/epel/zfs-release-2-3.el9.noarch.rpm

# Install ZFS (DKMS build — compiles the kernel module)
sudo dnf install -y zfs

# Load the kernel module immediately without rebooting
sudo modprobe zfs

# Verify the module is loaded
lsmod | grep zfs

# Check the ZFS version
zfs --version

To ensure the module loads automatically on boot, add it to the modules-load configuration.

echo "zfs" | sudo tee /etc/modules-load.d/zfs.conf

Step 2 — Create a ZFS Pool

A ZFS pool (zpool) is the top-level storage container. The simplest pool uses a single disk. For redundancy, use mirror (RAID-1) or raidz (RAID-5 equivalent) with multiple devices.

# Single-disk pool (no redundancy — suitable for testing)
sudo zpool create mypool /dev/sdb

# Mirror pool across two disks (recommended for production)
sudo zpool create mypool mirror /dev/sdb /dev/sdc

# RAIDZ pool across three disks (parity RAID)
sudo zpool create mypool raidz /dev/sdb /dev/sdc /dev/sdd

# Check pool health and status
sudo zpool status mypool

# List all pools
sudo zpool list

The pool is automatically mounted at /mypool after creation. The zpool status output shows each device, its state (ONLINE, DEGRADED, FAULTED), and read/write/checksum error counts.

Step 3 — Create Datasets and Enable Compression

ZFS datasets are logical filesystems within a pool. Each dataset can have its own properties — compression, quotas, and reservations — independent of other datasets.

# Create a dataset
sudo zfs create mypool/data

# Create a nested dataset (inherits parent properties)
sudo zfs create mypool/data/logs

# Enable LZ4 compression on the dataset (fast with good ratio)
sudo zfs set compression=lz4 mypool/data

# Confirm compression is active
sudo zfs get compression mypool/data

# Set a 50 GB quota so the dataset cannot exceed that size
sudo zfs set quota=50G mypool/data

# List all datasets and their used/available space
sudo zfs list

LZ4 is the recommended compression algorithm for most workloads — it compresses in real time with minimal CPU overhead and commonly achieves 2:1 ratios on text, logs, and database files.

Step 4 — Take and Roll Back Snapshots

ZFS snapshots are instantaneous, space-efficient, point-in-time copies of a dataset. They consume space only for the blocks that change after the snapshot is taken.

# Take a snapshot named "backup1"
sudo zfs snapshot mypool/data@backup1

# List all snapshots
sudo zfs list -t snapshot

# Simulate data loss
sudo rm -rf /mypool/data/important-files/

# Roll back to the snapshot (destroys changes made after the snapshot)
sudo zfs rollback mypool/data@backup1

# Delete an old snapshot when it is no longer needed
sudo zfs destroy mypool/data@backup1

Snapshot rollback is nearly instantaneous because ZFS simply adjusts its block pointer metadata — no data is physically moved.

Step 5 — Replicate Data with ZFS Send and Receive

zfs send serialises a snapshot (or an incremental diff) to a byte stream, which can be piped directly over SSH to zfs receive on a remote host. This is a popular, storage-efficient replication strategy.

# Take a snapshot to replicate
sudo zfs snapshot mypool/data@snap1

# Send the snapshot to a remote host over SSH
# The receiving host must have a ZFS pool named "backup"
sudo zfs send mypool/data@snap1 | ssh remotehost sudo zfs receive backup/data

# Incremental send — only transmit blocks changed since snap1
sudo zfs snapshot mypool/data@snap2
sudo zfs send -i mypool/data@snap1 mypool/data@snap2 | ssh remotehost sudo zfs receive backup/data

# Verify the replicated dataset on the remote host
ssh remotehost sudo zfs list

Incremental sends (-i) are far more bandwidth-efficient than full sends for ongoing replication jobs. For automated replication, consider tools such as sanoid/syncoid, which manage snapshots and incremental transfers as cron jobs.

Step 6 — Monitor Pool Health

Regularly scrubbing the pool validates all checksums and corrects any silent data corruption that ZFS detects and can repair from redundant copies.

# Start a scrub (reads every block and verifies its checksum)
sudo zpool scrub mypool

# Check scrub progress and final status
sudo zpool status mypool

# Display I/O statistics for the pool
sudo zpool iostat mypool 2

# Export the pool before moving disks to another system
sudo zpool export mypool

# Import it on the new system
sudo zpool import mypool

Conclusion

You have installed OpenZFS on RHEL 9, created a pool and datasets, enabled LZ4 compression, taken and rolled back snapshots, and replicated data over SSH using zfs send/receive. ZFS’s built-in integrity checking and snapshot capabilities make it a powerful complement to traditional backup strategies.

Next steps: How to Configure Network Bonding and Teaming on RHEL 9, How to Set Up Pacemaker and Corosync for High Availability on RHEL 9, and How to Configure VLAN Tagging with 802.1Q on RHEL 9.