NFS and iSCSI Storage Sharing
Share ZFS datasets over the network via NFS or iSCSI. Works on all kldload distros.
NFS and iSCSI on ZFS are fundamentally different from NFS and iSCSI on ext4.
On ext4, an NFS share is a directory on a disk. If the disk has a bad sector, the NFS client gets corrupt data silently. There's no snapshot — if a user deletes a file on the share, it's gone. There's no per-share quota — one share can fill the disk and starve all other shares. There's no replication — DR means rsync jobs and hope.
On ZFS, each NFS share is a dataset. Checksummed on every read — corrupt data is detected and auto-repaired from mirrors. Snapshotted hourly — users can access .zfs/snapshot/ and recover their own files without calling IT. Quotaed independently — one share can't fill the pool. Replicable with zfs send — the entire share, with all its snapshots, replicates to DR atomically over WireGuard.
iSCSI on ZFS gets the same benefits: a zvol is a block device backed by ZFS. Snapshot a VM's iSCSI disk before a migration. Clone it for testing — instant, zero cost. The VM doesn't know it's on ZFS. It sees a block device. Everything underneath is checksummed, compressed, and replicable.
NFS — File-level sharing
Server setup
# CentOS/RHEL
kpkg install nfs-utils
systemctl enable --now nfs-server
# Debian
kpkg install nfs-kernel-server
systemctl enable --now nfs-kernel-server
Create a shared dataset
# Create a ZFS dataset for sharing
zfs create -o mountpoint=/srv/nfs-share \
-o compression=lz4 \
rpool/srv/nfs-share
# Set ZFS NFS sharing (alternative to /etc/exports)
zfs set sharenfs="rw=@10.78.0.0/16,no_root_squash" rpool/srv/nfs-share
Or use traditional /etc/exports:
cat >> /etc/exports << 'EOF'
/srv/nfs-share 10.78.0.0/16(rw,no_root_squash,no_subtree_check,sync)
EOF
exportfs -ra
Open the firewall
# CentOS/RHEL
firewall-cmd --permanent --add-service=nfs
firewall-cmd --permanent --add-service=rpc-bind
firewall-cmd --permanent --add-service=mountd
firewall-cmd --reload
# Debian
nft add rule inet filter input tcp dport 2049 accept
Client setup
# CentOS/RHEL
kpkg install nfs-utils
# Debian
kpkg install nfs-common
# Mount
mkdir -p /mnt/shared
mount -t nfs 10.78.7.1:/srv/nfs-share /mnt/shared
# Verify
df -h /mnt/shared
# Persist in fstab
echo "10.78.7.1:/srv/nfs-share /mnt/shared nfs defaults,_netdev 0 0" >> /etc/fstab
Multiple exports with different permissions
# Read-write share for the team
zfs create rpool/srv/project-data
echo "/srv/project-data 10.78.0.0/16(rw,sync,no_subtree_check)" >> /etc/exports
# Read-only ISO library
zfs create rpool/srv/iso-library
echo "/srv/iso-library 10.78.0.0/16(ro,sync,no_subtree_check)" >> /etc/exports
# Home directories with root squash
echo "/home 10.78.0.0/16(rw,sync,no_subtree_check,root_squash)" >> /etc/exports
exportfs -ra
iSCSI — Block-level sharing
iSCSI presents a ZFS volume as a raw block device over the network. Useful for VMs, databases, or any workload that needs a dedicated block device.
Server setup (target)
# CentOS/RHEL
kpkg install targetcli
# Debian
kpkg install targetcli-fb
Create a ZFS volume (zvol)
# Create a 100GB zvol (thin-provisioned by default on ZFS)
zfs create -V 100G rpool/iscsi/vm-disk-1
# The block device appears at:
ls -l /dev/zvol/rpool/iscsi/vm-disk-1
# → /dev/zd0 (or similar)
Configure the iSCSI target
targetcli
# Inside targetcli:
/> cd /backstores/block
/backstores/block> create vm-disk-1 /dev/zvol/rpool/iscsi/vm-disk-1
/> cd /iscsi
/iscsi> create iqn.2026-03.com.kldload:storage.vm-disk-1
/> cd /iscsi/iqn.2026-03.com.kldload:storage.vm-disk-1/tpg1/luns
/iscsi/.../luns> create /backstores/block/vm-disk-1
/> cd /iscsi/iqn.2026-03.com.kldload:storage.vm-disk-1/tpg1/acls
/iscsi/.../acls> create iqn.2026-03.com.kldload:client1
/> saveconfig
/> exit
systemctl enable --now target
Open the firewall
# CentOS/RHEL
firewall-cmd --permanent --add-port=3260/tcp
firewall-cmd --reload
# Debian
nft add rule inet filter input tcp dport 3260 accept
Client setup (initiator)
# CentOS/RHEL
kpkg install iscsi-initiator-utils
# Debian
kpkg install open-iscsi
Set the client IQN:
echo "InitiatorName=iqn.2026-03.com.kldload:client1" > /etc/iscsi/initiatorname.iscsi
systemctl restart iscsid
Discover and connect
# Discover targets
iscsiadm -m discovery -t sendtargets -p 10.78.7.1:3260
# Login
iscsiadm -m node \
-T iqn.2026-03.com.kldload:storage.vm-disk-1 \
-p 10.78.7.1:3260 \
--login
# Find the new block device
lsblk
# sdb 8:16 0 100G 0 disk
# Format and mount (or use as a raw device for a VM)
mkfs.ext4 /dev/sdb
mkdir -p /mnt/iscsi-vol
mount /dev/sdb /mnt/iscsi-vol
Auto-connect at boot
iscsiadm -m node \
-T iqn.2026-03.com.kldload:storage.vm-disk-1 \
-p 10.78.7.1:3260 \
--op update -n node.startup -v automatic
systemctl enable iscsid
The WireGuard angle. All the NFS/iSCSI examples above use 10.78.0.0/16 — that's a WireGuard mesh subnet. On a kldload network, NFS and iSCSI traffic flows over encrypted WireGuard tunnels by default. Your file shares and block devices are encrypted in transit at the kernel level without any NFS/iSCSI-specific encryption config. No Kerberos. No stunnel. No IPsec. The tunnel is already there. The storage traffic rides on it.
Per-share datasets as service boundaries. Don't put all your NFS shares on one dataset. Create a dataset per share: rpool/srv/project-data, rpool/srv/iso-library, rpool/srv/home-dirs. Each one gets its own compression (zstd for documents, off for ISOs), its own quota (project can't eat the ISO library's space), its own snapshot schedule (hourly for project data, daily for ISOs), and its own replication target. The shares are independent storage domains. The NFS layer just exposes them.
ZFS advantages for storage sharing
Snapshots of shared data
# Snapshot the NFS share
zfs snapshot rpool/srv/nfs-share@hourly-$(date +%H)
# Expose snapshots to NFS clients (ZFS .zfs directory)
zfs set snapdir=visible rpool/srv/nfs-share
# Clients can access snapshots at:
# /mnt/shared/.zfs/snapshot/hourly-14/
Snapshot an iSCSI zvol
zfs snapshot rpool/iscsi/vm-disk-1@before-migration
# Clone for testing
zfs clone rpool/iscsi/vm-disk-1@before-migration rpool/iscsi/vm-disk-1-test
# New block device at /dev/zvol/rpool/iscsi/vm-disk-1-test
Compression
NFS data is compressed transparently by ZFS on the server side. Clients see uncompressed data:
zfs get compressratio rpool/srv/nfs-share
# NAME PROPERTY VALUE
# rpool/srv/nfs-share compressratio 2.31x
/mnt/shared/.zfs/snapshot/ and recover their own deleted files. No helpdesk ticket. No restore from backup. They navigate to the snapshot, copy the file back, and move on. This single feature eliminates the most common storage support request in any organization. Set snapdir=visible on every NFS share and tell your users about it. Watch your support tickets drop.Quotas per share
# Limit an NFS share to 500GB
zfs set quota=500G rpool/srv/nfs-share
# Guarantee 200GB (reservation)
zfs set reservation=200G rpool/srv/nfs-share
Troubleshooting
# NFS — show current exports
exportfs -v
showmount -e localhost
# NFS — client can't mount
rpcinfo -p <server-ip> # check RPC services running
mount -v -t nfs <server>:/path /mnt # verbose mount
# iSCSI — show active sessions
iscsiadm -m session
# iSCSI — disconnect
iscsiadm -m node -T <iqn> -p <ip>:3260 --logout
# iSCSI — show target config
targetcli ls