You mounted the share and got Permission denied
You set up a new Fedora machine to act as a file server for your home lab. You installed the packages, edited the exports file, and rebooted. The client machine hangs on the mount command. Or worse, the mount succeeds, but ls returns Permission denied even though the user has full access on the server. The error isn't a typo. It's SELinux or firewalld standing in the way.
NFS on Fedora works differently than a simple SMB share. The protocol relies on multiple services, dynamic ports, and strict security contexts. If one piece is missing, the whole stack fails silently or with a confusing error.
Run journalctl -xeu nfs-server first. Read the actual error before guessing.
How NFS and RPCbind work together
NFS doesn't use a single static port like SSH. The main NFS daemon listens on port 2049, but auxiliary services like mountd, statd, and nlockmgr use random high ports assigned at startup. rpcbind acts as the directory service. Clients ask rpcbind where the NFS helpers are listening. If rpcbind is down or blocked, the client can't find the services.
SELinux adds another layer. Even if the firewall allows traffic and the filesystem permissions look correct, SELinux will block the NFS daemon from reading files unless the directory has the correct security context. Fedora enforces this by default. The NFS daemon runs with a specific label. It can only access files with compatible labels. A directory created by a user has a user context. The NFS daemon cannot read it until the context changes to nfs_export_t.
Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/exports. Never edit /usr/lib/.
Install and configure the server
Here's how to install the server components and start the services.
sudo dnf install nfs-utils -y
# nfs-utils provides the NFS server daemon and the exportfs tool.
# -y skips the confirmation prompt for automated scripts.
sudo systemctl enable --now nfs-server rpcbind nfs-idmapd
# enable creates symlinks so services start on boot.
# --now starts the services immediately without a reboot.
# rpcbind is required for port mapping; NFS relies on it.
# nfs-idmapd maps UIDs to names for NFSv4 name resolution.
Here's how to define the share and apply the configuration.
sudo mkdir -p /srv/myshare
# Create the directory if it doesn't exist.
# /srv is the standard location for site-specific data served by the system.
echo "/srv/myshare 192.168.1.0/24(rw,sync,no_root_squash)" | sudo tee -a /etc/exports
# Define the export path, allowed subnet, and options.
# rw allows read-write access. sync ensures data is written to disk before responding.
# no_root_squash maps root on the client to root on the server. Use with caution.
sudo exportfs -ra
# -r reexports all directories. -a exports or unexports all.
# This applies changes without restarting the NFS service.
The no_root_squash option is dangerous on untrusted networks. It allows a root user on the client to write as root on the server. The default root_squash maps root to the nobody user, which is safer. Use no_root_squash only when you trust the client completely and need root-level operations.
Run exportfs -ra after every edit to /etc/exports. The service won't pick up changes until you do.
Open the firewall and set SELinux contexts
Fedora's default firewall blocks NFS by default. You must add the NFS service to the firewall to allow incoming connections on the required ports.
Here's how to open the firewall for NFS traffic.
sudo firewall-cmd --permanent --add-service=nfs
# Add the NFS service definition to the permanent zone configuration.
sudo firewall-cmd --permanent --add-service=mountd
# mountd handles mount requests and uses dynamic ports.
sudo firewall-cmd --permanent --add-service=rpc-bind
# rpc-bind allows the port mapper to respond to client queries.
sudo firewall-cmd --reload
# Reload is required to apply permanent changes to the running firewall.
# Without this, the rules exist in config but are not active.
firewall-cmd --reload after every rule change. Otherwise the runtime config and the persistent config diverge.
SELinux blocks access to the shared directory until you set the correct context. If your shared directory is not in a standard location, you must update the policy.
Here's how to set the SELinux context so the daemon can access the files.
sudo semanage fcontext -a -t nfs_export_t "/srv/myshare(/.*)?"
# Add a file context rule for the directory and its contents.
# nfs_export_t is the standard context for NFS shares.
# The regex matches the directory and all files inside it.
sudo restorecon -Rv /srv/myshare
# -R applies recursively. -v prints verbose output.
# restorecon applies the context rules to the actual filesystem.
SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. Disabling SELinux hides the problem and breaks security.
Mount the share on the client
Here's how to mount the share on the client machine.
sudo mkdir -p /mnt/nfs-share
# Create the local mount point directory.
sudo mount -t nfs server-ip:/srv/myshare /mnt/nfs-share
# -t nfs specifies the filesystem type.
# server-ip:/srv/myshare is the remote path.
# /mnt/nfs-share is the local directory where the share appears.
If the mount hangs, the firewall is likely blocking rpcbind. Check the server firewall rules. If the mount succeeds but you get Permission denied, check the SELinux context on the server.
Verify the connection
Here's how to confirm the exports are active and the mount is working.
showmount -e localhost
# Lists all exported directories and allowed clients.
# Run this on the server to verify exports are active.
df -h /mnt/nfs-share
# Shows the remote filesystem in the disk usage output.
# Confirms the mount is active and reporting size correctly.
Run journalctl -xeu nfs-server before blaming the network. The daemon logs the exact reason for a rejection.
Common errors and fixes
The mount command will refuse to proceed and print mount.nfs: access denied by server while mounting .... This usually means the client IP is not in /etc/exports, or the firewall is blocking the connection. Check the subnet mask in the exports file. Verify the firewall allows nfs, mountd, and rpc-bind.
If you see RPC: Program not registered, rpcbind is down or not responding. Restart rpcbind on the server. Check systemctl status rpcbind.
A Stale file handle error appears when the server reboots or the inode changes. The client cache holds a reference to the old inode. Remount the share on the client. Add soft to the mount options if you need the client to recover automatically, though hard is safer for data integrity.
Permission denied on write operations often points to SELinux. Run journalctl -t setroubleshoot on the server. Look for AVC denials related to nfsd or nfs_export_t. Fix the context with restorecon. Do not disable SELinux.
Read the denial in journalctl -t setroubleshoot. Disabling SELinux hides the problem and breaks security.
Choose the right protocol
Use NFS when you need high-performance file sharing between Linux machines on a trusted LAN. Use Samba when you need to share files with Windows or macOS clients that require SMB protocol support. Use SSHFS when you need to mount a remote directory over an encrypted SSH connection without configuring a dedicated server service. Use a local directory when the data only needs to be accessed by the machine itself.