Setting Up NFS Exports: Complete Configuration Guide
Master /etc/exports syntax, security options, and performance tuning. Platform-specific instructions for Ubuntu, Synology DSM, QNAP QTS, and TrueNAS.
NFS exports are the foundation of Linux file sharing. Whether you’re setting up a new file server, configuring a NAS appliance for migration, or troubleshooting mount failures, understanding /etc/exports is essential. This guide covers the syntax, security options, performance tuning, and platform-specific instructions.
NFS Basics
NFS (Network File System) allows a server to share directories over the network. Clients mount these shared directories as if they were local filesystems.
Components:
- Server — exports directories via
/etc/exports - Client — mounts exports via
mount -t nfs - Protocols — NFSv3 (stateless, UDP/TCP) and NFSv4 (stateful, TCP only)
/etc/exports Syntax
The export file defines what directories are shared and with what permissions:
/path/to/export client(options)
Basic Examples
# Share /data with a single host
/data 192.168.1.100(rw,sync,no_subtree_check)
# Share with an entire subnet
/data 192.168.1.0/24(rw,sync,no_subtree_check)
# Share with multiple clients (different options)
/data 192.168.1.0/24(rw,sync) 10.0.0.0/8(ro,sync)
# Share with any client (use cautiously)
/data *(ro,sync,no_subtree_check)
# Share with a hostname or DNS pattern
/data client.example.com(rw,sync)
/data *.example.com(ro,sync)
Watch the spacing
There must be no space between the client specification and the opening parenthesis. 192.168.1.0/24(rw) is correct. 192.168.1.0/24 (rw) exports to everyone with rw and to the subnet with default (ro) — a common and dangerous mistake.
Export Options
Read/Write Options
| Option | Description |
|---|---|
rw | Read-write access |
ro | Read-only access (default) |
sync | Reply only after changes committed to disk (safe, default) |
async | Reply before changes committed (faster but risks data loss on crash) |
User Mapping Options
| Option | Description |
|---|---|
root_squash | Map root (UID 0) to nobody (default, recommended) |
no_root_squash | Allow root access as root (dangerous) |
all_squash | Map all users to nobody |
anonuid=N | Set the UID for anonymous/squashed users |
anongid=N | Set the GID for anonymous/squashed users |
When to use no_root_squash
Only disable root squashing when the client genuinely needs root access — for example, a backup server that must preserve ownership across all files. For migration tools like syncopio, no_root_squash ensures permissions are preserved correctly during transfer.
Subtree Options
| Option | Description |
|---|---|
subtree_check | Verify files are in the exported subtree (slower, more secure) |
no_subtree_check | Skip subtree verification (faster, recommended for most cases) |
NFSv4 Options
| Option | Description |
|---|---|
fsid=0 | Mark as NFSv4 pseudo-root filesystem |
crossmnt | Allow traversal of mount points within the export |
sec=krb5 | Require Kerberos authentication |
sec=krb5i | Kerberos + integrity checking |
sec=krb5p | Kerberos + privacy (encryption) |
Platform-Specific Setup
Ubuntu / Debian
# Install NFS server
sudo apt update
sudo apt install nfs-kernel-server
# Create export directory
sudo mkdir -p /srv/data
sudo chown nobody:nogroup /srv/data
# Configure exports
echo '/srv/data 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)' | sudo tee -a /etc/exports
# Apply changes
sudo exportfs -ra
# Verify
sudo exportfs -v
# Start and enable
sudo systemctl enable --now nfs-kernel-server
RHEL / Rocky Linux / AlmaLinux
# Install NFS server
sudo dnf install nfs-utils
# Configure exports
sudo vi /etc/exports
# /srv/data 192.168.1.0/24(rw,sync,no_subtree_check)
# Apply and start
sudo exportfs -ra
sudo systemctl enable --now nfs-server
# Firewall rules
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=mountd
sudo firewall-cmd --permanent --add-service=rpc-bind
sudo firewall-cmd --reload
Synology DSM
- Open Control Panel > File Services > NFS
- Enable NFS service (select NFSv4.1 for best performance)
- Go to Shared Folders, select a folder, click Edit
- Open the NFS Permissions tab
- Click Create and configure:
- Hostname/IP:
192.168.1.0/24 - Privilege: Read/Write
- Squash: Map root to admin (or no mapping)
- Security: sys (or krb5 if using Kerberos)
- Enable asynchronous for better performance (if acceptable risk)
- Hostname/IP:
QNAP QTS
- Open Control Panel > Network & File Services > NFS Service
- Enable NFS and select the NFS version
- Go to Shared Folders, select the folder, click Edit Shared Folder Permission
- Switch to NFS Host Access tab
- Add a rule:
- Access Right: Read/Write
- Host/IP:
192.168.1.0/24 - Squash: ROOT_SQUASH or NO_ROOT_SQUASH
TrueNAS
- Navigate to Sharing > Unix Shares (NFS)
- Click Add
- Configure:
- Path: Select the dataset
- Networks:
192.168.1.0/24 - Maproot User:
root(for migration) ornobody - Maproot Group:
wheelornobody
- Click Submit
- Enable the NFS service under Services
Performance Tuning
Server-Side
# Increase NFS daemon threads (default is often 8)
# For busy servers, use 32-64
echo 64 > /proc/fs/nfsd/threads
# Or set permanently in /etc/nfs.conf
[nfsd]
threads = 64
# Monitor current NFS statistics
nfsstat -s
Client-Side Mount Options
# High-performance mount
mount -t nfs4 server:/export /mnt -o \
rsize=1048576,\ # 1MB read size
wsize=1048576,\ # 1MB write size
nconnect=8,\ # 8 TCP connections (Linux 5.3+)
hard,\ # Retry indefinitely on failure
intr,\ # Allow interrupt during retry
noatime,\ # Don't update access times
nocto # Don't refresh on open (read-heavy workloads)
| Option | Impact | When to Use |
|---|---|---|
nconnect=N | Biggest single improvement; N TCP connections per mount | Always (Linux 5.3+) |
rsize/wsize=1M | Larger I/O operations = fewer round-trips | Large file workloads |
noatime | Skip atime updates = fewer writes | Read-heavy workloads |
nocto | Skip revalidation on open = faster opens | When data rarely changes |
nconnect is a game-changer
A single NFS TCP connection typically maxes out at ~3-4 Gbps due to head-of-line blocking. With nconnect=8, you can saturate a 10Gbps or even 25Gbps link. This is the single most impactful mount option for throughput.
Troubleshooting
Essential Diagnostic Commands
# Show current exports
exportfs -v
# Show what the client sees as available
showmount -e server
# Check RPC services are running
rpcinfo -p server
# Test NFS mount
mount -t nfs4 -v server:/export /mnt
# Check NFS statistics
nfsstat -c # Client stats
nfsstat -s # Server stats
# Debug mount issues
mount -t nfs4 -v -o nfsvers=4 server:/export /mnt 2>&1
Common Issues
| Problem | Cause | Fix |
|---|---|---|
| ”mount.nfs: access denied” | Client IP not in export list | Check /etc/exports, run exportfs -ra |
| ”mount.nfs: Connection timed out” | Firewall blocking NFS ports | Open ports 2049 (NFS), 111 (rpcbind) |
| “Permission denied” on files | root_squash or UID mismatch | Use no_root_squash or map UIDs |
| Stale file handle | Export was changed while mounted | Remount on client: umount /mnt && mount ... |
| Very slow performance | Default mount options | Add nconnect=8,rsize=1048576,wsize=1048576 |
| ”Program not registered” | NFS server not running | systemctl start nfs-server |
Firewall Ports
For NFS to work across firewalls:
| Service | Port | Protocol |
|---|---|---|
| NFS | 2049 | TCP (v4), TCP/UDP (v3) |
| rpcbind | 111 | TCP/UDP |
| mountd | Dynamic* | TCP/UDP |
| statd | Dynamic* | TCP/UDP |
*For NFSv3 with firewalls, set static ports in /etc/nfs.conf:
[mountd]
port = 20048
[statd]
port = 32765
NFSv4 only needs port 2049 — one of its advantages over v3.
Further Reading
- NFS vs SMB: Performance, Security & When to Use Each — protocol comparison
- Data Migration: The Complete Guide — end-to-end methodology
- How to Migrate Your Synology NAS — NAS migration options
- The Complete rsync Guide — file transfer over NFS mounts