ZFS Storage Pool Setup: The Complete Home Lab Guide
ZFS is the filesystem that makes storage nerds emotional. Originally developed by Sun Microsystems, it combines a filesystem and volume manager into one integrated system. It checksums every block of data to prevent silent corruption, supports instant snapshots, built-in compression, and flexible RAID configurations — all without needing a hardware RAID controller.
For home labs, ZFS is the gold standard for storing anything you care about. But it has a learning curve, and getting the initial setup right matters. This guide walks through everything you need to know to build a ZFS storage pool that will serve your home lab well.
Why ZFS
Every filesystem stores data on disk. What makes ZFS different is what it does beyond that:
- Data integrity: ZFS checksums every data block and every metadata block. If a bit flips on disk (which happens more often than you'd think), ZFS detects it. With redundancy, it automatically repairs it.
- Snapshots: Take an instant, space-efficient point-in-time copy of your data. No downtime, no performance impact. Roll back to any snapshot instantly.
- Compression: Built-in, transparent compression. LZ4 compression is so fast it can actually improve performance (less data to write to disk).
- RAID built in: No hardware RAID card needed. ZFS handles all redundancy in software, with better data protection than traditional RAID.
- Copy-on-write: Data is never overwritten in place. This prevents corruption from power failures and makes snapshots essentially free.
The trade-off: ZFS is hungry for RAM. The general recommendation is 1 GB of RAM per TB of storage, plus whatever your OS and applications need. For a 16 TB pool, budget at least 16 GB for ZFS alone. ECC RAM is recommended but not strictly required — the ZFS community has moved past the old "you MUST use ECC" stance, though ECC is always preferable.
Pool Types Explained
A ZFS pool (zpool) is made up of one or more "vdevs" (virtual devices). The pool stripes data across vdevs. Each vdev can be a single disk, a mirror, or a RAID-Z group. Understanding vdevs is key to understanding ZFS.
Single Disk (No Redundancy)
zpool create tank /dev/sda
One disk, no redundancy. If the disk dies, your data is gone. Fine for scratch space or data you can easily re-download. Terrible for anything else.
Mirror (RAID 1 Equivalent)
zpool create tank mirror /dev/sda /dev/sdb
Two or more disks holding identical copies. You can lose any disk except the last one without data loss. 50% storage efficiency with 2 disks, 33% with 3, and so on.
Best for: Small pools (2-4 disks), maximum resilience, best random read performance.
RAID-Z1 (RAID 5 Equivalent)
zpool create tank raidz1 /dev/sda /dev/sdb /dev/sdc /dev/sdd
Distributes data across disks with single-parity redundancy. Can survive one disk failure. With 4 disks, you get 75% storage efficiency.
Best for: 3-5 disks where you want a balance of redundancy and capacity.
RAID-Z2 (RAID 6 Equivalent)
zpool create tank raidz2 /dev/sda /dev/sdb /dev/sdc /dev/sdd /dev/sde /dev/sdf
Double parity. Can survive two simultaneous disk failures. With 6 disks, you get 67% storage efficiency.
Best for: 5-8 disks, especially with larger drives where rebuild times are long.
RAID-Z3
Triple parity. Can survive three disk failures. Rarely needed in home labs but exists for large pools with high-capacity drives.
Practical Recommendations
| Disk Count | Recommended Layout | Storage Efficiency | Fault Tolerance |
|---|---|---|---|
| 2 | Mirror | 50% | 1 disk |
| 3 | RAIDZ1 | 67% | 1 disk |
| 4 | 2x Mirror | 50% | 1 per mirror |
| 4 | RAIDZ1 | 75% | 1 disk |
| 5-6 | RAIDZ2 | 60-67% | 2 disks |
| 6 | 3x Mirror | 50% | 1 per mirror |
| 8+ | 2x RAIDZ2 | 67-75% | 2 per vdev |
The 4-disk decision is the classic home lab dilemma: RAIDZ1 gives you 75% capacity but only tolerates one failure. Two mirrors give you 50% capacity but can tolerate one failure per mirror pair and deliver much better random I/O performance. If performance matters, go mirrors. If capacity matters, go RAIDZ1.
Creating Your First Pool
Identify Your Disks
# List all disks
lsblk
# Get disk IDs (use these instead of /dev/sdX — they're persistent)
ls -la /dev/disk/by-id/
# You'll see entries like:
# ata-WDC_WD40EFRX-68N32N0_WD-WCC7K0PL1234
# Use these full paths for your pool
Always use /dev/disk/by-id/ paths when creating ZFS pools. The /dev/sdX names can change between reboots as disks are detected in different orders. Disk IDs are permanent.
Create the Pool
# Mirror of two 4TB drives
zpool create -o ashift=12 tank \
mirror \
/dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-AAA \
/dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-BBB
# RAIDZ1 with four drives
zpool create -o ashift=12 tank \
raidz1 \
/dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-AAA \
/dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-BBB \
/dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-CCC \
/dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-DDD
The -o ashift=12 flag tells ZFS to use 4K sectors, which matches modern drives. Always include it — the default of ashift=9 (512-byte sectors) causes poor performance on modern drives, and you can't change it after pool creation.
Configure Pool Properties
# Enable LZ4 compression (recommended for almost everything)
zfs set compression=lz4 tank
# Set a reasonable record size for general use
zfs set recordsize=128k tank
# Enable extended attributes
zfs set xattr=sa tank
# Disable access time updates (reduces unnecessary writes)
zfs set atime=off tank
Create Datasets
Datasets are like sub-filesystems within your pool. Each can have its own settings (compression, quotas, snapshots). Use them instead of plain directories.
# Create datasets for different purposes
zfs create tank/media
zfs create tank/backups
zfs create tank/vms
zfs create tank/documents
# Set different record sizes for different workloads
zfs set recordsize=1M tank/media # Large files benefit from larger records
zfs set recordsize=64k tank/vms # VM images work well with 64k
zfs set recordsize=128k tank/backups # General purpose
# Set a quota to prevent one dataset from eating all the space
zfs set quota=2T tank/media
# Check your datasets
zfs list
Snapshots
Snapshots are ZFS's superpower. They're instant, nearly free (they only consume space as data changes), and make recovery trivial.
# Take a snapshot
zfs snapshot tank/documents@2026-02-09
# List snapshots
zfs list -t snapshot
# See how much space a snapshot is using
zfs list -t snapshot -o name,used,refer
# Roll back to a snapshot (destroys all changes since)
zfs rollback tank/documents@2026-02-09
# Clone a snapshot into a new dataset (for testing)
zfs clone tank/documents@2026-02-09 tank/documents-test
# Delete a snapshot
zfs destroy tank/documents@2026-02-09
Automated Snapshots
Don't manage snapshots manually. Use sanoid for automated snapshot management with configurable retention policies.
# Install sanoid
sudo apt install sanoid
# Configure /etc/sanoid/sanoid.conf
[tank/documents]
use_template = production
[tank/media]
use_template = media
[template_production]
hourly = 24
daily = 30
monthly = 6
autosnap = yes
autoprune = yes
[template_media]
daily = 7
monthly = 3
autosnap = yes
autoprune = yes
# Enable the sanoid timer
sudo systemctl enable --now sanoid.timer
Sanoid takes snapshots on schedule and automatically prunes old ones based on your retention policy. Its companion tool syncoid handles replication — sending snapshots to another ZFS system for off-site backup.
Scrubs
A scrub reads every block on every disk in the pool and verifies checksums. If it finds corruption on a redundant pool, it automatically repairs it using the good copy. This is the feature that makes ZFS worth the complexity.
# Run a scrub manually
zpool scrub tank
# Check scrub status
zpool status tank
# You'll see something like:
# scan: scrub in progress since Sun Feb 09 02:00:00 2026
# 1.23T scanned at 456M/s, 890G issued at 334M/s
# 0 repaired, 72.3% done
Schedule scrubs to run regularly. Monthly is the standard recommendation for home labs:
# Create a systemd timer (or use cron)
# /etc/cron.d/zfs-scrub
0 2 1 * * root /sbin/zpool scrub tank
On Proxmox, ZFS scrubs are already scheduled automatically — check with systemctl list-timers | grep zfs.
Monitoring Your Pool
# Pool health overview
zpool status
# Pool I/O statistics
zpool iostat -v 5 # Updates every 5 seconds
# Dataset space usage
zfs list
# Detailed pool information
zpool get all tank
# Check compression ratio
zfs get compressratio tank
A healthy pool shows state: ONLINE for the pool and every disk. If any disk shows DEGRADED, FAULTED, or UNAVAIL, you need to investigate immediately.
# Example of a healthy pool
# NAME STATE READ WRITE CKSUM
# tank ONLINE 0 0 0
# mirror-0 ONLINE 0 0 0
# ata-WDC...WD-AAA ONLINE 0 0 0
# ata-WDC...WD-BBB ONLINE 0 0 0
The READ, WRITE, and CKSUM columns show error counts. Any non-zero value in CKSUM is a red flag — it means ZFS detected (and with redundancy, repaired) silent data corruption. Non-zero READ or WRITE errors suggest a failing disk.
Adding Capacity
You can expand a ZFS pool by adding new vdevs. You cannot add individual disks to an existing RAIDZ vdev (though this feature is in development as of OpenZFS 2.3).
# Add another mirror pair to an existing pool
zpool add tank mirror \
/dev/disk/by-id/ata-WDC...-CCC \
/dev/disk/by-id/ata-WDC...-DDD
# Replace a failed disk
zpool replace tank \
/dev/disk/by-id/ata-OLD-DISK \
/dev/disk/by-id/ata-NEW-DISK
Common Mistakes
Not using disk-by-id paths: Using /dev/sda works until you add or remove a disk and everything shifts. Always use /dev/disk/by-id/.
Forgetting ashift=12: Create the pool with -o ashift=12. You can't change this later. Wrong ashift on modern drives tanks performance.
No scrubs: A pool without regular scrubs is a pool that might have silent corruption you don't know about. Schedule them monthly.
RAIDZ1 with large drives: Rebuilding a RAIDZ1 pool after a disk failure with 8+ TB drives can take days. During that rebuild, if another disk fails, you lose everything. Use RAIDZ2 for large drives.
Treating ZFS like backup: RAID is not backup. ZFS with mirrors protects against disk failure. It does not protect against accidental deletion, ransomware, or your house burning down. Use snapshots for accidental deletion recovery, and replicate to another system (or off-site) for real backup.
ZFS rewards you for doing the setup right the first time. Take the time to understand your vdev layout, enable compression, set up automated snapshots, and schedule scrubs. Your data will thank you.