6.8 KiB
6.8 KiB
| title | description | published | date | tags | editor | dateCreated |
|---|---|---|---|---|---|---|
| ZFS-NFS-Exports | Exporting NFS shares from ZFS datasets | true | 2026-02-01T20:45:40.210Z | markdown | 2026-02-01T20:45:40.210Z |
NFS + ZFS Configuration Fix
Problems Identified
- Boot order issue: NFS was starting before ZFS mounted the datasets
- Autofs recursive loop: The server was NFS-mounting its own exports back to itself via autofs, creating conflicts
- Mountpoint mismatch: ZFS datasets were mounting to
/srv/vault/*but NFS was trying to export from/export/*using bind mounts that didn't work properly - Child dataset mountpoints: When the parent dataset mountpoint changed, child datasets still had old mountpoints and weren't visible
Complete Solution
Step 1: Stop and Disable Autofs on NFS Server
sudo systemctl stop autofs
sudo systemctl disable autofs
Note: Autofs should only run on NFS clients, not on the server itself.
Step 2: Set ZFS Datasets to Mount Directly to /export/*
Instead of using bind mounts, configure ZFS to mount directly to the export paths:
sudo zfs set mountpoint=/export vault
sudo zfs set mountpoint=/export/Data vault/Data
sudo zfs set mountpoint=/export/Green vault/Green
sudo zfs set mountpoint=/export/Docker vault/docker
sudo zfs set mountpoint=/export/Common vault/Common
Step 3: Configure Child Dataset Mountpoints
For any child datasets (subdirectories under parent datasets), set their mountpoints explicitly:
sudo zfs set mountpoint=/export/Data/media/books vault/Data/media_books
sudo zfs set mountpoint=/export/Data/media/comics vault/Data/media_comics
Step 4: Unmount and Remount Datasets
Unmount children first, then parents, then remount all:
# Unmount child datasets first
sudo zfs unmount vault/Data/media_books
sudo zfs unmount vault/Data/media_comics
# Unmount parent datasets
sudo zfs unmount vault/Data
sudo zfs unmount vault/Green
sudo zfs unmount vault/docker
sudo zfs unmount vault/Common
# Remount all
sudo zfs mount -a
Step 5: Configure NFS Exports
Edit /etc/exports:
sudo nano /etc/exports
Content:
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
# NFSv4 - pseudo filesystem root
/export *(ro,fsid=0,crossmnt,no_subtree_check)
# Shares beneath the NFSv4 root
/export/Common *(fsid=4,rw,no_subtree_check,insecure)
/export/Data *(fsid=5,rw,no_subtree_check,insecure,crossmnt,nohide)
/export/Docker *(fsid=29,rw,no_root_squash,sync,no_subtree_check,insecure)
/export/Green *(fsid=30,rw,no_root_squash,no_subtree_check,insecure)
Key options explained:
crossmnt: Allows NFS to cross filesystem mount boundariesnohide: Makes child mounts visible through parent exportsno_subtree_check: Improves reliability and performance
Step 6: Configure NFS to Wait for ZFS at Boot
Create systemd override for NFS server:
sudo mkdir -p /etc/systemd/system/nfs-server.service.d/
sudo nano /etc/systemd/system/nfs-server.service.d/override.conf
Add this content:
[Unit]
After=zfs-import.target zfs-mount.service local-fs.target
Requires=zfs-import.target zfs-mount.service
This ensures NFS waits for ZFS to be fully mounted before starting.
Step 7: Reload and Restart Services
sudo systemctl daemon-reload
sudo exportfs -ra
sudo systemctl restart nfs-server
Step 8: Verify Configuration
On the server:
# Check ZFS mounts
zfs list -r vault
# Check what's actually mounted
mount | grep export
# Verify NFS exports
sudo exportfs -v
# Check content is visible
ls -la /export/Data/media/books/
On the client:
# Show available exports
showmount -e 192.168.5.10
# Mount NFS share
sudo mount -t nfs4 192.168.5.10:/ /mnt/znas
# Verify content
ls -la /mnt/znas/Data/media/books/
Adding New Datasets
When creating new datasets that need to be exported via NFS:
# Create dataset with correct mountpoint from the start
sudo zfs create -o mountpoint=/export/Data/new_folder vault/Data/new_folder
# The dataset will automatically mount and be visible via NFS
# due to the crossmnt and nohide options on the parent export
# Verify it's visible
ls -la /export/Data/new_folder/
No need to:
- Modify
/etc/exports(unless you need special permissions) - Create bind mounts in
/etc/fstab - Restart NFS (it will see the new mount automatically)
Troubleshooting
Datasets not visible via NFS
# Verify dataset is mounted
zfs list | grep dataset_name
# Check NFS can read it
sudo -u nobody ls -la /export/path/to/dataset/
# Restart NFS
sudo exportfs -ra
sudo systemctl restart nfs-server
Client shows empty directories
# On client, clear NFS cache
sudo umount -f /mnt/znas
sudo mount -t nfs4 192.168.5.10:/ /mnt/znas
# Or mount with no caching to test
sudo mount -t nfs4 -o noac,lookupcache=none 192.168.5.10:/ /mnt/znas
After reboot, exports are empty
# Verify ZFS mounted before NFS started
systemctl status zfs-mount.service
systemctl status nfs-server.service
# Check the override is in place
systemctl cat nfs-server.service | grep -A5 Unit
Important Notes
- Do not use bind mounts in
/etc/fstabfor ZFS datasets - let ZFS handle mounting directly - Keep autofs disabled on the NFS server to prevent recursive mount loops
- Child datasets must have their mountpoints explicitly set to be visible
- The
crossmntandnohideoptions are critical for NFSv4 to traverse ZFS dataset boundaries - Always set mountpoints when creating datasets to avoid having to fix them later
Configuration Files Reference
/etc/fstab
Should NOT contain bind mounts for /export/*. ZFS handles mounting directly.
Only keep system mounts:
# / was on /dev/nvme0n1p2 during curtin installation
/dev/disk/by-uuid/40c60952-0340-4a78-81f9-5b2193da26c6 / btrfs defaults 0 1
# /boot was on /dev/nvme0n1p3 during curtin installation
/dev/disk/by-uuid/4abb4efa-0b2b-4e4a-bcaf-78227db4628f /boot ext4 defaults 0 1
/dev/disk/by-uuid/d07437a0-3d0e-417a-a88e-438c603c2237 none swap sw 0 0
# /srv was on /dev/nvme0n1p5 during curtin installation
/dev/disk/by-uuid/c66e81ff-436e-4d6f-980b-6f4875ea7c8e /srv btrfs defaults 0 1
/etc/systemd/system/nfs-server.service.d/override.conf
[Unit]
After=zfs-import.target zfs-mount.service local-fs.target
Requires=zfs-import.target zfs-mount.service
/etc/exports
# NFSv4 - pseudo filesystem root
/export *(ro,fsid=0,crossmnt,no_subtree_check)
# Shares beneath the NFSv4 root
/export/Common *(fsid=4,rw,no_subtree_check,insecure)
/export/Data *(fsid=5,rw,no_subtree_check,insecure,crossmnt,nohide)
/export/Docker *(fsid=29,rw,no_root_squash,sync,no_subtree_check,insecure)
/export/Green *(fsid=30,rw,no_root_squash,no_subtree_check,insecure)