NFS (Network File System) lets one Linux server share a directory that other machines mount as if it were a local disk. It is the simplest way to give several servers access to the same files, for example shared uploads for a group of web servers or a central location for backups. In this tutorial you will set up an NFSv4 server on Ubuntu 24.04, export a directory to your private network, and mount it on a client both manually and at boot.
Prerequisites
You need two servers running Ubuntu 24.04 LTS, for example two CubePath VPS:
- NFS server: the machine that stores the files. This guide uses the private IP
10.0.0.10. - NFS client: the machine that mounts the share. This guide uses
10.0.0.20. - A non-root user with
sudoprivileges on both. - Both servers on the same private network (the examples use
10.0.0.0/24). Replace these addresses with your own.
WarningNFS with the default
sec=syssecurity trusts the user IDs the client sends and does not encrypt traffic. Only export shares over a private network you control, and never open port 2049 to the internet.
Step 1 - Installing the NFS server
On the server, install the kernel NFS server package:
sudo apt update
sudo apt install nfs-kernel-server
The package enables and starts the service. Confirm that it is running:
systemctl status nfs-server
● nfs-server.service - NFS server and services
Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; preset: enabled)
Active: active (exited) since Thu 2026-09-25 10:02:11 UTC; 12s ago
active (exited) is normal: the service only configures the in-kernel NFS server and then exits.
Step 2 - Creating the shared directory
Create the directory you will export. Keeping exports under /srv/nfs makes them easy to find:
sudo mkdir -p /srv/nfs/shared
By default NFS maps the client's root user to the unprivileged nobody user (this is called root squashing). Make that user the owner so that files written by root on a client do not fail with Permission denied:
sudo chown nobody:nogroup /srv/nfs/shared
sudo chmod 755 /srv/nfs/shared
Regular users on the client are mapped by numeric UID and GID, not by name. If a user deploy with UID 1001 exists on both machines, it owns the same files on both. Keep UIDs consistent across servers that share data, or you will see files owned by the wrong user.
Step 3 - Exporting the directory
Exports are defined in /etc/exports, one directory per line followed by the clients allowed to mount it and their options. Open the file:
sudo nano /etc/exports
Add this line at the end:
/srv/nfs/shared 10.0.0.0/24(rw,sync,no_subtree_check)
The client specification can be a single IP (10.0.0.20), a subnet (10.0.0.0/24) or several entries separated by spaces. The options mean:
| Option | Meaning |
|---|---|
rw | Clients can read and write. Use ro for a read-only share. |
sync | The server confirms a write only after it reaches disk. Safer than async, which can lose data if the server crashes. |
no_subtree_check | Disables subtree checking, which causes problems when files are renamed while open and is not recommended. |
root_squash is applied by default, so you do not need to write it. Avoid no_root_squash unless a specific workload needs it, because it gives root on any allowed client root access to the exported files.
Save the file, then apply the configuration and list the active exports:
sudo exportfs -ra
sudo exportfs -v
/srv/nfs/shared
10.0.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,root_squash,no_all_squash)
The output includes the defaults NFS added, such as root_squash and sec=sys. Run sudo exportfs -ra again every time you edit /etc/exports.
Step 4 - Allowing NFS through the firewall
NFSv4 only needs TCP port 2049. If UFW is active on the server, allow that port from your private subnet only:
sudo ufw allow from 10.0.0.0/24 to any port 2049 proto tcp
sudo ufw status
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
2049/tcp ALLOW 10.0.0.0/24
If ufw status prints Status: inactive, the rule is stored but not enforced. Make sure SSH is allowed before enabling UFW with sudo ufw enable.
Step 5 - Installing the NFS client
Switch to the client. Install the client utilities, which provide the mount.nfs helper:
sudo apt update
sudo apt install nfs-common
Create the local mount point:
sudo mkdir -p /mnt/nfs/shared
Step 6 - Mounting the share manually
Mount the export with NFSv4. The path after the colon is the full path of the directory on the server:
sudo mount -t nfs4 10.0.0.10:/srv/nfs/shared /mnt/nfs/shared
Check that it is mounted and which protocol version was negotiated:
df -h /mnt/nfs/shared
nfsstat -m
Filesystem Size Used Avail Use% Mounted on
10.0.0.10:/srv/nfs/shared 98G 1.2G 92G 2% /mnt/nfs/shared
/mnt/nfs/shared from 10.0.0.10:/srv/nfs/shared
Flags: rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.20,local_lock=none,addr=10.0.0.10
vers=4.2 confirms NFSv4.2, and the default rsize/wsize of 1 MB are already a good choice for most workloads.
Write a file as root on the client:
sudo touch /mnt/nfs/shared/from-client
ls -l /mnt/nfs/shared
-rw-r--r-- 1 nobody nogroup 0 Sep 25 10:20 from-client
The file belongs to nobody:nogroup, which shows root squashing in action. Back on the server, run ls -l /srv/nfs/shared and you will see the same file.
Unmount the share before configuring the permanent mount:
sudo umount /mnt/nfs/shared
Step 7 - Mounting the share at boot
To mount the share automatically, add it to /etc/fstab on the client. Back up the file first:
sudo cp /etc/fstab /etc/fstab.bak
sudo nano /etc/fstab
Add this line at the end:
10.0.0.10:/srv/nfs/shared /mnt/nfs/shared nfs4 defaults,_netdev,nofail 0 0
_netdev marks it as a network filesystem so systemd waits for the network before mounting it, and nofail lets the client boot normally if the NFS server is unreachable. The last two fields are 0 because fsck and dump do not apply to network filesystems.
Check the file, reload systemd and mount everything listed in it:
sudo findmnt --verify
sudo systemctl daemon-reload
sudo mount -a
findmnt /mnt/nfs/shared
TARGET SOURCE FSTYPE OPTIONS
/mnt/nfs/shared 10.0.0.10:/srv/nfs/shared nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,...
Finally, reboot the client with sudo reboot and run findmnt /mnt/nfs/shared again after reconnecting to confirm the share is mounted at boot.
TipIf the NFS server may reboot at the same time as its clients, add
x-systemd.automountto the options. systemd then mounts the share on first access instead of at boot, so a slow server does not delay the client's startup.
Step 8 - Tuning the number of server threads (optional)
The NFS server handles requests with a pool of kernel threads, 8 by default on Ubuntu 24.04. A server with many busy clients can benefit from more. Check the current value on the server:
cat /proc/fs/nfsd/threads
8
To raise it, edit /etc/nfs.conf:
sudo nano /etc/nfs.conf
Find the [nfsd] section, uncomment the threads line and set the new value:
[nfsd]
threads=16
Restart the server and confirm the change:
sudo systemctl restart nfs-server
cat /proc/fs/nfsd/threads
Troubleshooting
mount.nfs: access denied by server while mounting. The client's IP is not covered by the export. Check sudo exportfs -v on the server, make sure the client connects from the address or subnet you listed (a private IP, not its public one), then run sudo exportfs -ra after fixing /etc/exports.
mount.nfs: Connection timed out. Port 2049 is blocked. Test it from the client with nc -zv 10.0.0.10 2049, then check the server's firewall with sudo ufw status and that the service is running with systemctl status nfs-server.
Permission denied when writing. Either root squashing is mapping you to nobody, which cannot write to a root-owned directory, or the UID of your client user does not match the owner on the server. Compare id your_user on both machines and fix ownership on the server with chown.
Stale file handle. The exported directory was deleted or recreated on the server while mounted. Unmount and remount the share on the client; if the unmount hangs, use sudo umount -l /mnt/nfs/shared.
The client hangs when the server is down. NFS mounts are hard by default, so I/O waits until the server returns instead of returning errors that could corrupt data. This is the correct behavior for writable shares; bring the server back rather than switching to soft.
Conclusion
You now have an NFSv4 server exporting /srv/nfs/shared to a private subnet, protected by UFW and root squashing, and a client that mounts the share at boot without hanging if the server is unavailable. Next, you could add more clients by repeating Steps 5 to 7, keep the exported directory on a dedicated data disk, or set up Samba if Windows and macOS machines also need access to the files.
