--- title: "How to Set Up an NFS Server and Client on Ubuntu 24.04" description: "Export a directory over NFSv4 from an Ubuntu 24.04 server, restrict it to your private network with UFW and mount it on a client at boot through /etc/fstab." category: "Storage Management" language: en source: https://cubepath.com/docs/storage-management/nfs-storage-configuration-server-and-client updated: 2026-09-25 --- # How to Set Up an NFS Server and Client on Ubuntu 24.04 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. > Warning: NFS with the default `sec=sys` security 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: ```bash sudo apt update sudo apt install nfs-kernel-server ``` The package enables and starts the service. Confirm that it is running: ```bash systemctl status nfs-server ``` ```output ● 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: ```bash 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`: ```bash 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: ```bash sudo nano /etc/exports ``` Add this line at the end: ```text /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: ```bash sudo exportfs -ra sudo exportfs -v ``` ```output /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: ```bash sudo ufw allow from 10.0.0.0/24 to any port 2049 proto tcp sudo ufw status ``` ```output 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: ```bash sudo apt update sudo apt install nfs-common ``` Create the local mount point: ```bash 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: ```bash 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: ```bash df -h /mnt/nfs/shared nfsstat -m ``` ```output 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: ```bash sudo touch /mnt/nfs/shared/from-client ls -l /mnt/nfs/shared ``` ```output -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: ```bash 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: ```bash sudo cp /etc/fstab /etc/fstab.bak sudo nano /etc/fstab ``` Add this line at the end: ```text 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: ```bash sudo findmnt --verify sudo systemctl daemon-reload sudo mount -a findmnt /mnt/nfs/shared ``` ```output 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. > Tip: If the NFS server may reboot at the same time as its clients, add `x-systemd.automount` to 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**: ```bash cat /proc/fs/nfsd/threads ``` ```output 8 ``` To raise it, edit `/etc/nfs.conf`: ```bash sudo nano /etc/nfs.conf ``` Find the `[nfsd]` section, uncomment the `threads` line and set the new value: ```ini [nfsd] threads=16 ``` Restart the server and confirm the change: ```bash 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.