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 sudo privileges on both.
  • Both servers on the same private network (the examples use 10.0.0.0/24). Replace these addresses with your own.

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:

OptionMeaning
rwClients can read and write. Use ro for a read-only share.
syncThe server confirms a write only after it reaches disk. Safer than async, which can lose data if the server crashes.
no_subtree_checkDisables 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.

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.