NFS (Network File System) is a distributed filesystem protocol that allows clients to access files over a network as if they were on local storage.
Addresses below are RFC 5737 documentation ranges or placeholders - swap in your own.
Table of Contents#
- Overview
- NFSv3 vs NFSv4 Comparison
- Server Installation
- Server Configuration
- Export Parameters
- Firewall Configuration
- Client Configuration
- Client Mount Options
- Kerberos Authentication
- Performance Tuning
- Troubleshooting
- See Also
- Sources
1. Overview#
NFS enables transparent file sharing between UNIX/Linux systems using a server-client model. The server exports directories, and clients mount them over the network. NFS uses Remote Procedure Calls (RPC) for communication.
Key characteristics:
- Kernel-level implementation - high performance with minimal userspace overhead
- Stateless (v3) or stateful (v4) - NFSv4 tracks open files and locks
- POSIX-compatible - supports standard file permissions, locking, and access semantics
- Widely supported - available on virtually every Linux distribution, macOS, and Windows (via Services for NFS)
2. NFSv3 vs NFSv4 Comparison#
| Feature | NFSv3 | NFSv4 / NFSv4.1 / NFSv4.2 |
|---|---|---|
| Statefulness | Stateless (separate lock protocol) | Stateful (integrated locking) |
| Ports | Multiple (2049, 111, dynamic mountd/lockd/statd) | Single port 2049 only |
| Firewall friendliness | Poor - requires rpcbind + dynamic ports | Excellent - only port 2049 |
| Authentication | AUTH_SYS (UID/GID), optional Kerberos | AUTH_SYS and Kerberos (native) |
| Pseudo-filesystem | No - clients mount specific paths | Yes - single namespace with fsid=0 root |
| ACL support | POSIX ACLs via sideband | NFSv4 ACLs (richer model, Windows-compatible) |
| Delegation | No | Yes - clients can cache aggressively when granted delegation |
| pNFS (parallel NFS) | No | Yes (v4.1+) - data striped across multiple servers |
| Server-side copy | No | Yes (v4.2) - copy_file_range offload |
| Mandatory locking | No | Yes |
Recommendation: Use NFSv4 or later unless legacy clients require NFSv3. NFSv4.2 adds server-side copy and sparse file support.
3. Server Installation#
Debian/Ubuntu#
sudo apt update
sudo apt install -y nfs-kernel-serverRHEL/CentOS/Rocky#
sudo dnf install -y nfs-utilsArch Linux#
sudo pacman -S nfs-utilsEnable and Start#
sudo systemctl enable --now nfs-serverFor NFSv4 only (disable NFSv3):
# /etc/nfs.conf
[nfsd]
vers3=n
vers4=y
vers4.1=y
vers4.2=y4. Server Configuration#
Creating a Shared Directory#
# Create the export directory
sudo mkdir -p /srv/nfs/share
# Set ownership (nobody:nogroup for anonymous access)
sudo chown nobody:nogroup /srv/nfs/share
sudo chmod 755 /srv/nfs/shareConfiguring Exports#
Edit /etc/exports to define shared directories and access rules:
# NFSv4 pseudo-root (recommended)
/srv/nfs *(ro,fsid=0,no_subtree_check)
# Shared directory under the pseudo-root
/srv/nfs/share 192.0.2.0/24(rw,sync,no_subtree_check,no_root_squash)
/srv/nfs/share 198.51.100.0/24(ro,sync,no_subtree_check)Apply changes:
sudo exportfs -ravNFSv4 Pseudo-Filesystem#
NFSv4 uses a pseudo-filesystem rooted at the export with fsid=0. Clients mount relative to this root:
# Server exports:
/srv/nfs *(fsid=0,ro,no_subtree_check)
/srv/nfs/share 192.0.2.0/24(rw,sync,no_subtree_check)
/srv/nfs/home 192.0.2.0/24(rw,sync,no_subtree_check)
# Client mounts the pseudo-root:
mount -t nfs4 server:/ /mnt/nfs
# Or mounts a specific sub-export:
mount -t nfs4 server:/share /mnt/share5. Export Parameters#
| Parameter | Description |
|---|---|
fsid=0 | Marks the NFSv4 pseudo-root export |
ro | Read-only access |
rw | Read-write access |
sync | Write data to disk before replying (default, safe) |
async | Reply before data is written to disk (faster, risk of corruption on crash) |
no_subtree_check | Disables subtree checking (default, improves performance and reliability) |
subtree_check | Enables subtree checking (not recommended) |
root_squash | Maps remote root (UID 0) to anonymous user (default) |
no_root_squash | Allows remote root to retain root privileges |
all_squash | Maps all remote users to anonymous |
no_all_squash | Preserves remote user UIDs/GIDs (default) |
anonuid=<uid> | UID for the anonymous user |
anongid=<gid> | GID for the anonymous user |
crossmnt | Automatically exports filesystems mounted under this export |
sec=<mode> | Security flavor: sys, krb5, krb5i, krb5p |
insecure | Allows connections from ports above 1024 |
6. Firewall Configuration#
NFSv4 (Port 2049 Only)#
sudo firewall-cmd --add-service=nfs --permanent
sudo firewall-cmd --reloadNFSv3 (Multiple Ports)#
NFSv3 requires additional services. Fix their ports for firewall rules:
# /etc/nfs.conf - pin auxiliary service ports
[mountd]
port=20048
[lockd]
port=32803
udp-port=32803
[statd]
port=32764sudo firewall-cmd --add-service=nfs --permanent
sudo firewall-cmd --add-service=mountd --permanent
sudo firewall-cmd --add-service=rpc-bind --permanent
sudo firewall-cmd --add-port=32803/tcp --permanent
sudo firewall-cmd --add-port=32803/udp --permanent
sudo firewall-cmd --add-port=32764/tcp --permanent
sudo firewall-cmd --add-port=32764/udp --permanent
sudo firewall-cmd --reload7. Client Configuration#
Installing the Client#
# Debian/Ubuntu
sudo apt install -y nfs-common
# RHEL/CentOS/Rocky
sudo dnf install -y nfs-utils
# Arch Linux
sudo pacman -S nfs-utilsMounting an NFS Share#
# NFSv4 mount
sudo mount -t nfs4 server:/share /mnt/nfs
# NFSv3 mount (explicit version)
sudo mount -t nfs -o vers=3 server:/srv/nfs/share /mnt/nfsPersistent Mounting via fstab#
# NFSv4
server:/share /mnt/nfs nfs4 defaults,_netdev 0 0
# NFSv3
server:/srv/nfs/share /mnt/nfs nfs vers=3,defaults,_netdev 0 0Automount with systemd#
# /etc/systemd/system/mnt-nfs.mount
[Unit]
Description=NFS Share Mount
After=network-online.target
Wants=network-online.target
[Mount]
What=server:/share
Where=/mnt/nfs
Type=nfs4
Options=defaults,_netdev
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now mnt-nfs.mount8. Client Mount Options#
| Option | Description | Recommended Value |
|---|---|---|
hard | Retry NFS requests indefinitely (default) | Yes for production |
soft | Return error after retrans retries | Only for non-critical mounts |
intr | Allow signals to interrupt hung NFS operations | Deprecated in modern kernels |
rsize=<bytes> | Maximum read request size | 1048576 (1 MiB) for NFSv4 |
wsize=<bytes> | Maximum write request size | 1048576 (1 MiB) for NFSv4 |
timeo=<decisec> | Timeout before first retransmission (in 1/10 sec) | 600 (60 sec) for TCP |
retrans=<n> | Number of retransmissions before returning error (soft) or major timeout (hard) | 2 (default) |
sec=<mode> | Security mechanism: sys, krb5, krb5i, krb5p | sys (default) or krb5p |
noatime | Do not update access times | Recommended for performance |
nolock | Disable NLM locking (NFSv3 only) | Only for read-only or specific workloads |
actimeo=<sec> | Attribute cache timeout | 60 for low-change data |
nconnect=<n> | Number of TCP connections (kernel 5.3+, NFSv4.1+) | 4-16 for throughput |
_netdev | Wait for network before mounting | Always use in fstab |
9. Kerberos Authentication#
Kerberos provides strong authentication and optional encryption for NFS, replacing the trust-based AUTH_SYS (UID/GID) model.
Security Levels#
| Level | Authentication | Integrity | Encryption | Performance |
|---|---|---|---|---|
sec=sys | UID/GID (no auth) | No | No | Fastest |
sec=krb5 | Kerberos ticket | No | No | Minimal overhead |
sec=krb5i | Kerberos ticket | Yes (checksums) | No | Moderate overhead |
sec=krb5p | Kerberos ticket | Yes | Yes (full payload) | Significant overhead |
Server-Side Setup#
# Install Kerberos client libraries
sudo apt install -y krb5-user # Debian/Ubuntu
sudo dnf install -y krb5-workstation # RHEL
# Create NFS service principal in your KDC
kadmin -q "addprinc -randkey nfs/<server-fqdn>@REALM"
kadmin -q "ktadd -k /etc/krb5.keytab nfs/<server-fqdn>@REALM"
# Export with Kerberos security
# /etc/exports
/srv/nfs/share 192.0.2.0/24(rw,sync,sec=krb5p,no_subtree_check)
# Enable and start gssproxy (or rpc.gssd)
sudo systemctl enable --now nfs-server gssproxyClient-Side Setup#
# Install Kerberos client
sudo apt install -y krb5-user nfs-common
# Extract the keytab for the client
kadmin -q "addprinc -randkey nfs/<client-fqdn>@REALM"
kadmin -q "ktadd -k /etc/krb5.keytab nfs/<client-fqdn>@REALM"
# Enable gssproxy or rpc.gssd
sudo systemctl enable --now gssproxy
# Mount with Kerberos
sudo mount -t nfs4 -o sec=krb5p server:/share /mnt/nfsID Mapping (NFSv4)#
NFSv4 maps UIDs/GIDs to user@domain strings. Configure the domain on both server and client:
# /etc/idmapd.conf
[General]
Domain = example.comsudo systemctl restart nfs-idmapd10. Performance Tuning#
Read/Write Buffer Sizes#
Modern kernels negotiate up to 1 MiB by default. Verify and set explicitly:
sudo mount -t nfs4 -o rsize=1048576,wsize=1048576 server:/share /mnt/nfsNFS Server Threads#
The default number of NFS server threads (8) is often too low for production:
# /etc/nfs.conf
[nfsd]
threads=64Or at runtime:
echo 64 | sudo tee /proc/fs/nfsd/threadsMultiple TCP Connections (nconnect)#
Available in kernel 5.3+ with NFSv4.1. Opens multiple TCP connections to parallelize I/O:
sudo mount -t nfs4 -o nconnect=8 server:/share /mnt/nfsJumbo Frames#
If the network supports it, enable MTU 9000 on both server and client for reduced per-packet overhead:
sudo ip link set eth0 mtu 9000Caching with CacheFS (cachefilesd)#
Local disk caching for NFS mounts reduces network traffic for read-heavy workloads:
sudo apt install -y cachefilesd
sudo systemctl enable --now cachefilesd
# Mount with fsc option
sudo mount -t nfs4 -o fsc server:/share /mnt/nfsMonitoring NFS Performance#
# Client-side statistics
nfsstat -c
# Server-side statistics
nfsstat -s
# Per-mount statistics
mountstats /mnt/nfs
# Real-time RPC statistics
nfsstat -l11. Troubleshooting#
| Issue | Cause | Solution |
|---|---|---|
mount.nfs: access denied by server | Client IP not in exports, or export options mismatch | Verify /etc/exports; run exportfs -v to confirm active exports; check sec= matches client |
Stale file handle (ESTALE) | Server-side export was re-exported, filesystem was remounted, or inode table changed | Unmount and remount on the client: umount -l /mnt/nfs && mount /mnt/nfs |
mount.nfs: Connection timed out | Firewall blocking NFS port, server not running, or wrong server address | Verify nfs-server is running; check port 2049 (NFSv4) or rpcbind (NFSv3); test with rpcinfo -p <server> |
Permission denied on files | UID/GID mismatch between server and client, or root_squash in effect | Align UIDs/GIDs, use no_root_squash if appropriate, or configure idmapd for NFSv4 |
| Very slow read/write performance | Small rsize/wsize, single NFS thread, or high latency | Increase rsize/wsize to 1048576; increase server threads; use nconnect= for parallelism |
mount.nfs: requested NFS version or transport protocol is not supported | NFSv3 disabled on server but client requesting v3, or vice versa | Specify version explicitly: mount -o vers=4.2; check /etc/nfs.conf on server |
| Lock recovery taking too long after reboot | NFSv3 NLM grace period (default 90 seconds) | Reduce grace period in /etc/nfs.conf: [lockd] grace-period=30; use NFSv4 which has faster lease-based recovery |
rpc.gssd: ERROR: No credentials found | Missing Kerberos keytab or expired ticket | Verify /etc/krb5.keytab exists with correct principal; run kinit or check gssproxy |
Client hangs on hard mount | Server is down and client retries indefinitely | Use soft mount for non-critical data, or hard,timeo=600 to increase timeout; fix server availability |