Deploying NFS on Rocky Linux 9: Server Exports and Client Mounts (Container-Tested)
When files must be shared across multiple Linux machines, NFS is one of the least-fuss solutions: the server exports a directory, the client mounts it as a local path, and reads and writes feel just like working on a local disk. This post walks the complete NFS chain on Rocky Linux 9 — install, export, service startup, client mount, and cross-machine read/write — with the server and client each running in a rockylinux:9 container (custom subnet on the same host). All output below comes from that live run; the three typical errors in this post were deliberately reproduced by making mistakes on purpose.
Planning and Prerequisites
Fix the two machines’ roles, directories, and IPs first; every command below follows this table:
| Server | Role | Directory | IP address |
|---|---|---|---|
| Rocky Linux 9 | Server | /export/nfs | 192.168.254.2 |
| Rocky Linux 9 | Client | /data | 192.168.254.3 |
Confirm three things before starting: the two machines can reach each other over the network (mutual ping succeeds); you have root or sudo privileges; and ports 2049 (NFS) and 111 (rpcbind) are not blocked by the firewall on the server side. A typical intranet meets all three.
Note: when reproducing in containers, the export directory must sit on a filesystem that supports NFS export (I used tmpfs), otherwise
exportfs -rfails withdoes not support NFS export; physical xfs/ext4 filesystems don’t have this problem.
Step 1: Install nfs-utils on Both Ends
On Rocky 9, server and client install the same package; dnf install pulls rpcbind in as a dependency:
1 | dnf install -y nfs-utils |
Verification point: run rpm -q nfs-utils; you should see a version starting with nfs-utils-2.5.4-42.el9 (this run measured 2.5.4-42.el9.aarch64).
Step 2: Create the Server Directory and Write the Export Rule
Create the export directory and open up write permissions:
1 | mkdir -p /export/nfs |
chmod 666 makes the directory readable and writable by all users so client writes don’t get stuck on permissions. Then write the sharing rule into /etc/exports by adding this line:
1 | /export/nfs 192.168.254.0/24(rw,no_root_squash,no_all_squash,sync) |
What the rule means: share /export/nfs with the 192.168.254.0/24 subnet; the parameters in parentheses are, in order —
rw: allow reads and writesno_root_squash: client root users keep their root identity, no privilege-dropping mappingno_all_squash: ordinary users keep their original identity, no uniform mapping to the anonymous usersync: writes hit disk synchronously — safer data, slightly slower
Make sure the subnet matches the client’s actual IP: this line only allows 192.168.254.x machines to mount; clients outside the subnet are refused by the server (see the live error in the failure-escape section below). Apply the config after editing:
1 | exportfs -r |
Verification point: exportfs -r exits with no error output; running exportfs -v then lists /export/nfs together with all its parameters.

Step 3: Start the Services on the Server
NFS depends on the RPC machinery, so both rpcbind and nfs-server must start — rpcbind first:
1 | systemctl start rpcbind |
Verification point: rpcinfo -p localhost should list the registration lines for nfs (program 100003, port 2049) and mountd — this service table is only visible while rpcbind is working; without rpcbind the table is empty and clients naturally cannot connect. Then run showmount -e localhost locally; you should see your own export list.

In production, also enable both services at boot so the share doesn’t quietly vanish after a restart:
1 | systemctl enable rpcbind nfs-server |
Step 4: Client Queries the Export List and Mounts
The client also needs nfs-utils installed and rpcbind started (an NFSv3 mount needs local rpc.statd running for file locking; without it the mount fails — see the second entry in the failure-escape section). Then create the mount point and first ask the server what it exports:
1 | systemctl start rpcbind |
Verification point: showmount -e should list /export/nfs 192.168.254.0/24 — seeing the list proves both the network and the RPC path work; get this step passing before mounting and you save most of the troubleshooting time.

After confirming /export/nfs is visible, mount:
1 | mount -t nfs 192.168.254.2:/export/nfs /data/ |
Verification point: in df -hT /data/, the filesystem column should show nfs, and the device column should read 192.168.254.2:/export/nfs.
After a successful mount, files written to /data actually land in the server’s /export/nfs. Cross-machine read/write verification: on the client run echo "hello from client" > /data/write-test.txt, then on the server run cat /export/nfs/write-test.txt — you should see the same line of content, proof the file really crossed the network onto the server’s disk.

Historical Version Differences (CentOS 7)
If you are still on CentOS 7, the whole flow is unchanged except for three details: the package manager is yum (from el8 on, dnf replaces yum with compatible usage); the nfs-utils version is much older (1.3.0 on el7, with slightly older protocol defaults — for cross-version mounts prefer an explicit -o vers=3 or vers=4); and the startup commands are exactly the same, still systemctl start rpcbind nfs-server. The original article was written on CentOS 7.6, and this same command set ran cleanly on a 7.6 client back then.
Post-Install Verification and Failure Escapes
The final acceptance of the whole chain comes down to one test: the client writes, and the server can read it. To roll back, tear it down in reverse order:
1 | # Unmount on the client |
Four high-frequency errors, each reproduced live or handled against real symptoms during this container run:
mount.nfs: access denied by server: the client IP is not inside the export subnet. Tested by changing the export to 192.168.0.0/24 and mounting from 192.168.254.3 — this error reproduced reliably. Check the /etc/exports subnet against the client’s actual IP; after fixing,exportfs -rapplies it, no service restart needed.mount.nfs: rpc.statd is not running: the client’s local rpcbind/statd isn’t up; NFSv3 mounts need it for lock negotiation. Most common on minimal installs and in containers: runsystemctl start rpcbindand confirm rpc.statd is running; as a temporary bypass you can mount with-o nolock(at the cost of losing cross-machine file locking).- Mount succeeds but writes fail with Permission denied: the export options don’t grant the root identity. Tested by reverting the options to the default
root_squash— client root writes immediately failed with Permission denied because root had been mapped to nobody. Check whetherno_root_squashis configured as needed, and whether the directory permissions (chmod 666) were actually applied. showmounttimes out or clnt_create fails: the server’s rpcbind or nfs-server isn’t fully up. Go back to the server and checksystemctl statusand firewall access to port 111.

Wrap-up
Looking back at the whole chain: install nfs-utils, write /etc/exports, start rpcbind + nfs-server, confirm with showmount on the client, then mount — every step has a matching “what you should see.” A few lessons to close: no_root_squash lets client root keep its root identity — in testing, turning it off blocked writes immediately, so enable it only on trusted intranets; after editing exports, exportfs -r applies immediately, no nfs-server restart needed; and asking first with showmount -e before mounting cuts most of the time spent troubleshooting failed mounts.
This post was rewritten from the author’s CSDN blog articles originally published between 2020 and 2024 on CSDN.