NFS4 on Linux: Solving Common Export, Mounting, and Security Issues


2 views

The NFS4 exports syntax can be particularly confusing when dealing with multiple exports on a single line. The manpage states that options specified after a dash affect "all subsequent exports on that line only." Here's what that means in practice:

# Affects only /export1 and /export2
/path1 -rw,sync 192.168.1.0/24
/path2 -ro,async 192.168.1.0/24

# Different behavior - options after dash apply to all paths on this line
/path1 /path2 -rw,sync 192.168.1.0/24

The fsid=0 parameter has caused much confusion in NFS4 implementations. While it was crucial in earlier versions, modern NFS4 servers (kernel 3.0+) often don't require it for the root export. However, it's still recommended for:

  • Better backward compatibility
  • Explicitly marking the root of your NFS export tree
  • Preventing potential issues with some client implementations

The ability to mount non-exported directories under an exported parent is actually by design in NFS4. This behavior stems from NFS4's pseudo-filesystem approach where:

# Even though only /exp/distr is exported, clients can access:
/exp/distr/archlinux
/exp/distr/debian
# And potentially /exp/users if permissions allow

To restrict this, you need to either:

  1. Use the 'no_pseudo' export option
  2. Implement explicit export restrictions for each subdirectory
  3. Adjust filesystem permissions accordingly

The rmtab behavior you observed raises valid security concerns. Modern best practices recommend:

# Disable rmtab completely in /etc/nfs.conf:
[mountd]
manage-gids = false
no-nfs-owner = true
# Add this to prevent rmtab updates:
echo "NEED_RMTAB=no" >> /etc/default/nfs-common

For monitoring active mounts, consider these alternatives:

  • netstat -an | grep 2049
  • ss -tnp | grep nfsd
  • Custom scripts parsing /proc/fs/nfsd/clients/*

Here's a recommended exports setup for your scenario:

# /etc/exports
/exp       192.168.1.0/24(fsid=0,rw,async,no_subtree_check,no_root_squash,crossmnt)
/exp/distr 192.168.1.0/24(rw,async,no_subtree_check,no_root_squash,no_pseudo)
/exp/users 192.168.1.0/24(ro,all_squash,anonuid=65534,anongid=65534)

And corresponding fstab entries:

# /etc/fstab
/dev/disk/by-label/users  /mnt/users  ext4  defaults,nosuid,nodev  0  0
/dev/disk/by-label/distr  /mnt/distr  ext4  defaults,nosuid,nodev  0  0
/mnt/users                /exp/users  none  bind,nosuid,nodev      0  0
/mnt/distr                /exp/distr  none  bind,nosuid,nodev      0  0

Remember to run exportfs -ra after changes and verify with exportfs -v.

For secure client mounting:

# Recommended client mount options:
mount -t nfs4 -o \
rw,hard,noatime,nodiratime,proto=tcp,timeo=600,retrans=2 \
server:/exp/distr /mnt/nfs/distr

Key options explained:

  • hard: Critical for data integrity
  • noatime/nodiratime: Reduces metadata writes
  • proto=tcp: More reliable than UDP
  • timeo/retrans: Adjust for your network conditions

The phrase "subsequent exports on that line only" in the exports(5) manpage refers to how default options (prefixed with '-') apply to multiple exports declared on the same line. For example:

/shared/data -rw,sync client1(rw) client2(ro)

Here, -rw,sync becomes the default for both client1 and client2, with each client able to override these defaults.

While older NFS4 implementations required fsid=0 to designate the root of the pseudo-filesystem, modern Linux kernels (since ~2012) handle this automatically. However, including it explicitly doesn't hurt:

/export fsid=0,ro 192.168.1.0/24

The exception is when you need to maintain compatibility with very old clients or special configurations.

Your observation about mounting /exp/users despite it not being exported stems from NFS4's pseudo-filesystem behavior. When you export /exp with fsid=0, clients can traverse to any subdirectory unless explicitly restricted. To prevent this:

/exp 192.168.1.0/24(fsid=0,ro,no_subtree_check)
/exp/distr 192.168.1.0/24(rw)
/exp/users 192.168.1.0/24(noaccess)

The noaccess option explicitly blocks access while maintaining the directory structure.

The /var/lib/nfs/rmtab situation presents several issues:

  1. Disable rmtab entirely by adding --no-nfs-version 3 to /etc/nfs.conf under the [nfsd] section
  2. Regularly clean stale entries with: echo > /var/lib/nfs/rmtab
  3. For NFS4-only environments, consider: mount -t nfs4 -o vers=4 server:/export /mnt

Here's a complete working configuration for secure NFS4 exports:

# /etc/exports
/exported fsid=0,ro,no_subtree_check 192.168.1.0/24
/exported/data rw,no_root_squash 192.168.1.10
/exported/backups ro 192.168.1.20

# /etc/nfs.conf
[nfsd]
debug=0
vers4=y
vers3=n

After modifying these files, restart services:

systemctl restart nfs-server
exportfs -arv