How to Install and Configure NFS Server on Fedora: Securely Share Directories on Your Local Network with SELinux and firewalld

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

Set Up NFS Server in 5 Minutes (Quick Start)

I run NFS on a Fedora server to share the /data directory with a dev team of about six people, who mount it from their local machines every morning. The initial setup only takes a few commands:

# Install NFS server
sudo dnf install nfs-utils -y

# Create the shared directory
sudo mkdir -p /srv/nfs/shared
sudo chmod 755 /srv/nfs/shared

# Declare exports
echo "/srv/nfs/shared 192.168.1.0/24(rw,sync,no_subtree_check)" | sudo tee -a /etc/exports

# Start and enable the service
sudo systemctl enable --now nfs-server

# Reload exports
sudo exportfs -ra

If you’re testing on a trusted local network, go ahead and try mounting from a client right away to see if the connection works. But on a default Fedora system — where SELinux is Enforcing and firewalld are both enabled out of the box — skipping the next two sections will almost certainly leave you debugging for hours with the mount still failing.

Step-by-Step Breakdown

1. How NFS Works

After installation, you have three core daemons: rpc.nfsd accepts and handles connections from clients, rpc.mountd manages mount requests, and rpcbind acts as the port mapper between them. Check the status right after starting:

sudo systemctl status nfs-server
sudo showmount -e localhost    # view the current list of exports

2. /etc/exports Syntax

The /etc/exports file is where you declare which directories to share, which hosts can access them, and with what permissions. A few real-world examples:

# Share read-write with the entire subnet
/srv/nfs/shared  192.168.1.0/24(rw,sync,no_subtree_check)

# Share read-only with a specific machine
/srv/nfs/docs    192.168.1.100(ro,sync)

# Share with multiple hosts, different permissions
/srv/nfs/public  192.168.1.0/24(rw,sync) 10.0.0.5(ro,sync)

Key options worth knowing:

  • rw / ro: read-write or read-only
  • sync: write to disk before replying to the client — safer than async
  • no_subtree_check: disables subtree checking, reduces errors when files are renamed while a client has them open
  • all_squash: maps all UID/GID to nfsnobody — useful when you don’t want client users to have real permissions
  • no_root_squash: root on the client equals root on the server; only use this when truly necessary and with a clear understanding of the risks

After every edit to this file, reload with:

sudo exportfs -ra
sudo exportfs -v    # view exports with their active options

3. Configuring firewalld

This is the most commonly skipped step. NFS needs more services opened than you might expect — not just port 2049:

# Open the required services for NFS
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=rpc-bind
sudo firewall-cmd --permanent --add-service=mountd

sudo firewall-cmd --reload

# Confirm
sudo firewall-cmd --list-services

If you want to restrict access to just the internal subnet rather than opening everything, use the internal zone:

sudo firewall-cmd --permanent --zone=internal --add-service=nfs
sudo firewall-cmd --permanent --zone=internal --add-service=rpc-bind
sudo firewall-cmd --permanent --zone=internal --add-service=mountd
sudo firewall-cmd --permanent --zone=internal --add-source=192.168.1.0/24
sudo firewall-cmd --reload

4. SELinux — It’s Not as Hard as You Think

I used to habitually run setenforce 0 to disable SELinux and move on quickly. After reading about several production server breaches caused by disabled security defaults, I dropped that habit entirely. For NFS, you just need to enable the right booleans:

# View all NFS-related booleans
getsebool -a | grep nfs

# Allow read-write and read-only exports
sudo setsebool -P nfs_export_all_rw 1
sudo setsebool -P nfs_export_all_ro 1

# If clients mount NFS as a home directory
sudo setsebool -P use_nfs_home_dirs 1

If your shared directory is not under /srv/nfs (for example, you’re using /data/shared), you need to assign the correct SELinux context:

# Assign the NFS context to a custom directory
sudo semanage fcontext -a -t nfs_t "/data/shared(/.*)?" 
sudo restorecon -Rv /data/shared

# Verify the context is correct
ls -lZ /data/shared

When you get a “Permission denied” error despite correct firewall configuration, this is the first command I run:

sudo ausearch -m avc -ts recent | tail -30

Advanced: Fixing Ports and NFS v4

Fixing Ports for Stable Firewall Rules

By default, rpc.mountd and nlockmgr use dynamic ports — they change after every restart, which breaks firewall rules after a reboot. Pin them in /etc/nfs.conf:

sudo nano /etc/nfs.conf
[mountd]
port=892

[lockd]
port=32803
udp-port=32769

[statd]
port=662

Open these ports in the firewall and restart:

sudo firewall-cmd --permanent --add-port=892/tcp
sudo firewall-cmd --permanent --add-port=892/udp
sudo firewall-cmd --permanent --add-port=32803/tcp
sudo firewall-cmd --permanent --add-port=32769/udp
sudo firewall-cmd --permanent --add-port=662/tcp
sudo firewall-cmd --permanent --add-port=662/udp
sudo firewall-cmd --reload
sudo systemctl restart nfs-server

Mounting from a Client

# Install client tools on the client machine
sudo dnf install nfs-utils -y

# Test manual mount
sudo mount -t nfs 192.168.1.10:/srv/nfs/shared /mnt/test
df -h /mnt/test
ls -la /mnt/test

# Unmount after testing
sudo umount /mnt/test

To mount automatically at boot, add an entry to /etc/fstab:

192.168.1.10:/srv/nfs/shared  /mnt/shared  nfs  defaults,_netdev  0 0

The _netdev option matters more than you’d think — it tells systemd to wait for the network to be ready before attempting the mount. Without it, the client machine may hang at boot if the NFS server hasn’t come up yet.

Practical Tips After 6 Months in Production

Monitor connected clients:

sudo showmount -a              # list currently mounted clients
sudo nfsstat -s                # server statistics
sudo nfsstat -c                # client statistics (run on the client machine)

Handling UID/GID mismatch — this comes up more often than you’d expect: the user on the server and client have different UIDs, so the mount succeeds but you still get permission denied with no obvious reason:

# Check the UID of the current user
id username

# Solution: map everyone to a fixed UID/GID
/srv/nfs/shared 192.168.1.0/24(rw,sync,all_squash,anonuid=1000,anongid=1000)

Use NFS v4.2 to get the latest features (sparse file support, server-side copy, improved security):

sudo mount -t nfs -o vers=4.2 192.168.1.10:/srv/nfs/shared /mnt/shared

# Confirm the version in use
cat /proc/mounts | grep nfs

Back up exports before experimenting:

sudo cp /etc/exports /etc/exports.bak.$(date +%Y%m%d)

Check which NFS versions the server supports:

cat /proc/fs/nfsd/versions
# Output: +2 +3 +4 +4.1 +4.2

# Disable NFS v2 if not needed (reduces attack surface)
echo "-2" | sudo tee /proc/fs/nfsd/versions

I’ve been using Fedora as my primary development machine for two years and I’m quite happy with its package update cadence. NFS on Fedora looks more complex than on other distros because of SELinux and firewalld. But that’s precisely why this setup is more robust — two layers of default protection that many distros simply don’t have. Spending an extra 20 minutes configuring things correctly upfront will save you many hours of debugging down the road.

Share: