📅 October 14, 2026 · 🏷️ Storage / Networking

How to Set Up NFS Server on Linux VPS — File Sharing Guide

NFS Server setup on Linux VPS for file sharing between servers

NFS (Network File System) is the standard Linux file sharing protocol that lets multiple VPS instances share the same filesystem as if it were local storage. It's ideal for shared storage between app servers, web clusters, and backup targets where you need better performance than Samba in a Linux-only environment.

This guide covers installing NFS Server on Ubuntu 22.04/24.04 and Debian 12, configuring /etc/exports, mounting from the client side, setting up autofs for on-demand mounting, and security hardening.

NFS Architecture Overview

NFS uses a client-server model:

Note: NFS version 4 (NFSv4) uses only port 2049, making it far easier to firewall than NFSv3 which uses dynamic ports. Always prefer NFSv4 for new deployments.

Installing NFS Server (Ubuntu/Debian)

1. Install the package

# Update package list
sudo apt update

# Install NFS kernel server
sudo apt install -y nfs-kernel-server

# Check service status
sudo systemctl status nfs-kernel-server

2. Create export directories

# Create directories to share
sudo mkdir -p /srv/nfs/shared
sudo mkdir -p /srv/nfs/data

# Set ownership (for clients using nobody/nogroup)
sudo chown nobody:nogroup /srv/nfs/shared
sudo chmod 755 /srv/nfs/shared

# Verify
ls -la /srv/nfs/

3. Configure /etc/exports

sudo nano /etc/exports

Add your export rules:

# Share with a single IP (recommended for production)
/srv/nfs/shared  192.168.1.100(rw,sync,no_subtree_check,no_root_squash)

# Share with an entire subnet
/srv/nfs/data    192.168.1.0/24(rw,sync,no_subtree_check)

# Read-only for a backup client
/srv/nfs/shared  192.168.1.200(ro,sync,no_subtree_check)

Common export options explained:

OptionDescription
rwRead and write access
roRead-only access
syncWrite to disk immediately (safer than async)
no_subtree_checkDisable subtree checking (reduces overhead)
no_root_squashRoot on client = root on server
root_squashRoot on client maps to nobody (default, safer)
all_squashAll users map to anonymous user

4. Apply exports and restart

# Apply exports
sudo exportfs -a

# Restart and enable the service
sudo systemctl restart nfs-kernel-server
sudo systemctl enable nfs-kernel-server

# View active exports
sudo exportfs -v

Firewall Configuration

# Allow NFS port only from client IPs (NFSv4)
sudo ufw allow from 192.168.1.100 to any port 2049
sudo ufw allow from 192.168.1.0/24 to any port 2049

# Also allow rpcbind if using NFSv3
sudo ufw allow from 192.168.1.0/24 to any port 111

sudo ufw reload
sudo ufw status
Security Warning: Never expose port 2049 to the internet. NFS has no built-in transport encryption. Restrict exports to private network ranges (10.x.x.x, 192.168.x.x) only.

Installing and Mounting on the NFS Client

Install NFS client

# Ubuntu/Debian client
sudo apt install -y nfs-common

# CentOS/RHEL client
sudo yum install -y nfs-utils

Test mount

# Create mount point
sudo mkdir -p /mnt/nfs-shared

# Mount for testing
sudo mount -t nfs 192.168.1.10:/srv/nfs/shared /mnt/nfs-shared

# Test file write
echo "NFS test" | sudo tee /mnt/nfs-shared/test.txt
cat /mnt/nfs-shared/test.txt

# Check mount info
df -h /mnt/nfs-shared
mount | grep nfs

Persistent mount with /etc/fstab

sudo nano /etc/fstab
# NFS mount (NFSv4)
192.168.1.10:/srv/nfs/shared  /mnt/nfs-shared  nfs4  defaults,_netdev,rw,hard,timeo=600,retrans=2  0  0
# Test fstab
sudo mount -a
df -h | grep nfs

Auto-mount with autofs (better for network mounts)

# Install autofs
sudo apt install -y autofs

# Edit /etc/auto.master
sudo nano /etc/auto.master
# Add this line
/mnt/nfs  /etc/auto.nfs  --timeout=60
# Create /etc/auto.nfs
sudo nano /etc/auto.nfs
# format: mount_point  options  server:export
shared  -rw,soft,intr  192.168.1.10:/srv/nfs/shared
data    -ro             192.168.1.10:/srv/nfs/data
# Restart autofs
sudo systemctl restart autofs
sudo systemctl enable autofs

# Test — autofs mounts on first access
ls /mnt/nfs/shared/

Performance Tuning

# Use larger buffer sizes for better throughput
sudo mount -t nfs4 -o rsize=1048576,wsize=1048576,hard,timeo=600 \
  192.168.1.10:/srv/nfs/shared /mnt/nfs-shared

# View NFS statistics
nfsstat -c  # client stats
nfsstat -s  # server stats

# Check I/O latency
iostat -xm 1 5
Tip: Using async instead of sync in exports gives maximum write performance but risks data loss if the server crashes before flushing. Only use it for data that can be regenerated.

Verifying NFS Server is Working Correctly

# Check service status
sudo systemctl status nfs-kernel-server

# View active exports with client details
sudo exportfs -v

# Show current NFS connections
sudo showmount -e localhost

# From client — list what server exports
showmount -e 192.168.1.10

# Check RPC services
rpcinfo -p localhost

# View NFS server stats
cat /proc/net/rpc/nfsd
Tip: Use nfsstat -s to view server statistics and nfsiostat for real-time I/O throughput. If mounts hang, always check firewall rules and rpcbind service first.

Troubleshooting Common Errors

Error: "mount.nfs: Connection timed out"

The firewall on the server is blocking port 2049, or the NFS service is not running.

# Check NFS service on server
sudo systemctl status nfs-kernel-server

# Check port 2049 is listening
sudo ss -tlnp | grep 2049
sudo ufw status | grep 2049

# Open the port if blocked
sudo ufw allow from CLIENT_IP to any port 2049
sudo ufw reload

Error: "mount.nfs: access denied by server while mounting"

The client's IP address doesn't match what's defined in /etc/exports.

# Find the client's actual IP (could be public or private)
# On client:
ip addr show
curl ifconfig.me

# Check current exports on server
sudo exportfs -v

# Fix /etc/exports with the correct IP, then reload
sudo nano /etc/exports
sudo exportfs -ra

# Debug via syslog
sudo tail -f /var/log/syslog | grep nfs

Error: "Stale file handle"

The server restarted or exports changed, making the client's existing mount invalid.

# Force unmount on client
sudo umount -f -l /mnt/nfs-shared

# Remount
sudo mount -t nfs4 192.168.1.10:/srv/nfs/shared /mnt/nfs-shared

Error: "rpc.statd is not running"

The NFS locking daemon is not running (required for NFSv3).

# Start rpcbind and nfs-common
sudo systemctl start rpcbind
sudo systemctl enable rpcbind
sudo systemctl restart nfs-common

# NFSv4 doesn't need rpc.statd
# Use mount -t nfs4 instead of nfs

Slow performance / High latency

Buffer sizes are too small or network latency is high.

# Increase rsize/wsize to 1MB
sudo umount /mnt/nfs-shared
sudo mount -t nfs4 -o rsize=1048576,wsize=1048576,hard \
  192.168.1.10:/srv/nfs/shared /mnt/nfs-shared

# Benchmark throughput
dd if=/dev/zero of=/mnt/nfs-shared/test.bin bs=1M count=100 oflag=direct
rm /mnt/nfs-shared/test.bin

Frequently Asked Questions

What's the difference between NFS and Samba? Which should I use?

NFS is designed for Linux-to-Linux sharing with lower overhead and better performance for server environments. Samba is better when you need to share files with Windows clients or require Active Directory authentication. For pure Linux server clusters or datacenter environments, NFS is the preferred choice.

Is NFS secure? What additional steps are needed?

NFSv4 is significantly more secure than NFSv3, but NFS still lacks built-in transport encryption. For encrypted NFS, use it over a WireGuard or OpenVPN VPN tunnel, or implement Kerberos authentication (NFSv4 with sec=krb5). The most critical security step is restricting exports to specific trusted IPs only — never export to 0.0.0.0/0.

How do I prevent NFS mounts from hanging after a server reboot?

Use the soft option instead of hard in fstab so operations time out instead of hanging indefinitely. Always add the _netdev fstab option so the OS waits for network before mounting. Even better: use autofs, which only mounts on actual access, naturally handling server reboots without hanging the client.