NFS (Network File System) is the standard protocol for sharing filesystems between Linux and Unix systems. It allows remote directories to be mounted and accessed as if they were local, making it fundamental to shared storage architectures, home directory sharing, and NAS (Network Attached Storage) integration.
NFS Architecture
NFS uses a client-server model built on top of RPC (Remote Procedure Call):
- NFS Server: Exports one or more directories to the network
- NFS Client: Mounts the exported directories and accesses them
- rpcbind: Port mapper daemon — translates RPC program numbers to network ports
- mountd: Handles mount and unmount requests from clients
- nfsd: The actual NFS server daemon that handles file operations
NFS Versions
| Version | Default in | Protocol | Security | Key Features |
|---|---|---|---|---|
| NFSv2 | Old systems | UDP | None | Basic file sharing |
| NFSv3 | RHEL 5 | UDP/TCP | None | Large files, async writes, better error handling |
| NFSv4 | RHEL 6/7 | TCP only | Kerberos (optional) | Stateful, ACLs, single port (2049), delegation |
| NFSv4.1 | RHEL 7+ | TCP | Kerberos | pNFS (parallel NFS), sessions, better clustering |
NFSv3 vs NFSv4 Key Differences
- NFSv3: Stateless — server does not track client connections. Simpler but no session recovery. Uses multiple ports (111, 2049, plus dynamic ports for mountd, lockd, statd).
- NFSv4: Stateful — server maintains session state. Uses only port 2049 (no rpcbind needed for v4). Supports file locking natively. Supports ACLs. Requires only TCP.
NFS Server Configuration — Step by Step
# Install NFS packages:
# yum install nfs-utils -y
# Create directory to share:
# mkdir -p /nfs/shared
# chmod 755 /nfs/shared # basic permissions
# chown nobody:nobody /nfs/shared # for anonymous access
# For SELinux:
# chcon -t public_content_rw_t /nfs/shared # if clients need write access
# chcon -t public_content_t /nfs/shared # if read-only
# The /etc/exports file:
# Format: directory client(options)
# vim /etc/exports
# Export to a specific hostname:
/nfs/shared client9.example.com(rw,sync,no_root_squash)
# Export to entire domain:
/nfs/shared *.example.com(rw,sync)
# Export to IP subnet:
/nfs/shared 192.168.1.0/24(rw,sync,no_subtree_check)
# Export read-only to everyone:
/nfs/shared *(ro,sync)
# Multiple clients with different permissions:
/nfs/data db1.example.com(rw,sync) web.example.com(ro,sync)
Export Options Explained
| Option | Meaning |
|---|---|
| rw | Read-write access |
| ro | Read-only access (default if unspecified) |
| sync | Write to disk before replying to client. Safer, slightly slower. |
| async | Reply before writing to disk. Faster, risk of data loss on server crash. |
| root_squash | Map remote root (UID 0) to anonymous user (nobody). Default. Prevents remote root from owning server files. |
| no_root_squash | Remote root has root access on server. Use only on trusted private networks. |
| all_squash | Map all remote UIDs to anonymous user (for public shares) |
| no_subtree_check | Disable subtree checking (faster, recommended for most exports) |
| secure | Require clients to use ports below 1024 (default, ensures privileged client) |
| insecure | Allow client ports above 1024 (needed for some NFS clients) |
# Apply exports without restarting NFS:
# exportfs -rv # re-read /etc/exports, verbose
# exportfs -a # export all
# exportfs -ua # unexport all (maintenance)
# View current exports:
# exportfs -v
# Start NFS (RHEL 7):
# systemctl start nfs-server rpcbind
# systemctl enable nfs-server rpcbind
# Start NFS (RHEL 6):
# service rpcbind start
# service nfs start
# chkconfig rpcbind on
# chkconfig nfs on
NFS Client Configuration
# Install:
# yum install nfs-utils -y
# Discover what a server exports:
# showmount -e nfs-server.example.com
# showmount -e 192.168.1.11
# Mount manually (temporary):
# mkdir -p /mnt/nfs_data
# mount -t nfs nfs-server:/nfs/shared /mnt/nfs_data
# mount -t nfs4 nfs-server:/nfs/shared /mnt/nfs_data # force NFSv4
# mount -o ro,sync nfs-server:/nfs/shared /mnt/readonly
# Mount with additional options:
# mount -o rw,sync,hard,intr nfs-server:/share /mnt/nfs
# hard = keep retrying if server unreachable (default, prevents data loss)
# soft = return error if server unreachable (use with timeout)
# intr = allow interrupt signals during hard mount (Ctrl+C works)
# noatime = don't update access times (performance)
# Permanent mount (/etc/fstab):
nfs-server:/nfs/shared /mnt/nfs_data nfs defaults,_netdev 0 0
# _netdev = wait for network before mounting (critical for NFS mounts)
# NFSv4 mount (single port, no rpcbind):
nfs-server:/nfs/shared /mnt/nfs_data nfs4 defaults,_netdev 0 0
Autofs — On-Demand Mounting
Autofs automatically mounts NFS shares when they are accessed and unmounts them after a timeout period. Benefits:
- Reduces system load (unmounted shares consume no resources)
- Handles NFS server unavailability gracefully (no stale mounts)
- Used for home directories in LDAP/NIS environments
- Users only get the mount they actually access
# Install:
# yum install autofs -y
# Main map: /etc/auto.master
# Format: mount_point map_file [options]
/misc /etc/auto.misc --timeout=60
/home /etc/auto.home --timeout=300
# Map file: /etc/auto.misc
# Format: subdirectory [-options] location
nfs -rw,sync nfs-server:/nfs/shared
# Creates /misc/nfs → mounted when accessed, unmounted after 60 seconds
# Home directory map: /etc/auto.home
# Format: username -options server:/path/to/homedir
* -rw,sync nfs-server:/home/&
# & substitutes for the matched username
# So "raju" at /home/raju → mounts nfs-server:/home/raju
# Start autofs:
# systemctl start autofs
# systemctl enable autofs
# Test (accessing the directory triggers the mount):
# ls /misc/nfs # triggers mount
# ls /misc/ # before access: empty
# cd /misc/nfs && ls # mounts here
# sleep 65 && ls /misc/ # after timeout: unmounted
# Reload autofs after config change (without restart):
# systemctl reload autofs
# Verify active mounts:
# service autofs status
# cat /proc/mounts | grep autofs
NFS Security — Kerberos Authentication
By default, NFS uses AUTH_SYS (trust client-supplied UID/GID). NFSv4 with Kerberos provides real authentication.
# NFS security levels (specified in /etc/exports):
/nfs/secure *.example.com(rw,sync,sec=krb5)
# sec= options:
# sys = AUTH_SYS (default, trusts client UID/GID — no real auth)
# krb5 = Kerberos v5 authentication only
# krb5i = Kerberos + integrity (tamper detection)
# krb5p = Kerberos + integrity + encryption (most secure)
Firewall Configuration for NFS
# NFSv4 uses only port 2049 (TCP):
# firewall-cmd --permanent --add-service=nfs # port 2049
# firewall-cmd --reload
# NFSv3 requires additional ports:
# firewall-cmd --permanent --add-service=mountd # rpc.mountd
# firewall-cmd --permanent --add-service=rpc-bind # portmapper
# firewall-cmd --reload
# For RHEL 6 (iptables), fix NFSv3 ports in /etc/sysconfig/nfs:
RQUOTAD_PORT=875
LOCKD_TCPPORT=32803
LOCKD_UDPPORT=32769
MOUNTD_PORT=892
STATD_PORT=662
# Then add fixed port rules to /etc/sysconfig/iptables:
-A INPUT -m state --state NEW -p tcp --dport 2049 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 111 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 875 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 892 -j ACCEPT
NFS Troubleshooting
# Client cannot mount:
# 1. Check server is exporting:
# showmount -e server_ip
# exportfs -v
# 2. Check RPC services:
# rpcinfo -p server_ip # list RPC services and ports
# 3. Check firewall:
# firewall-cmd --list-all # verify NFS service is open
# 4. Check SELinux on server:
# sealert -a /var/log/audit/audit.log
# getsebool -a | grep nfs
# 5. Check mount syntax:
# mount -v server:/share /mnt/nfs # verbose
# Performance issues:
# NFS is slow → check network bandwidth, try async option, increase rsize/wsize:
# mount -o rsize=65536,wsize=65536,hard,intr server:/share /mnt/nfs
# Stale NFS mount (server went away):
# umount -f -l /mnt/nfs # lazy force unmount
# fuser -ck /mnt/nfs # kill processes using it first
# Statistics:
# nfsstat # NFS call statistics
# nfsiostat 1 5 # I/O statistics per mount