Running NFS Behind a Firewall: Setting Up Static NFS Ports on unRAID

Just taking some notes to outline my plan to deploy NFS mounts to my DMZ servers. I am posting these notes because I think people might benefit from seeing the background information/theory that goes into writing a guide. If you like this note post format and want me to do more, please let me know.

As mentioned in a recent post, I am planning on mounting NFS shares in my Proxmox VMs. The problem is that some of these VMs, the ones in my DMZ, are isolated from my unRAID server via an access control list (ACL). You can read more about my ACL set up here:

The Problem: NFS Ports Aren’t Static

On the surface, this is simple enough, just whitelist (permit) the NFS ports through the ACL, but the problem is that NFS uses rpcbind to semi-randomly assigned ports. Therefore, we need to restrict the port range, thus effectively assigning static ports for NFS on unRAID.

Red Hat, as usual, provides an excellent general overview:

The Solution: Static NFS Ports

Basically, we’ll need to permit (TCP/UDP) port 2049 for NFS and port 111 for rpcbind/sunrpc. We’ll also need to permit (TCP/UDP) MOUNTD_PORT and STATD_PORT, as well as TCP port LOCKD_TCPPORT and UDP LOCKD_UDPPORT.

These ports (MOUNTD_PORT, STATD_PORT, LOCKD_TCPPORT, and LOCKD_UDPPORT) are the ports that will need to be statically assigned in unRAID.

Note that if/when unRAID gets NFSv4, we shouldn’t have to worry about mountd, statd, or lockd. Unfortunately, unRAID (as of 6.9.0-beta1) does not support NFSv4 despite documentation claiming otherwise. Until it does, we’ll need to handle the static port mappings.

Thankfully, it appears someone has already done this (thanks Arch!):

#!/bin/bash

DEFAULT_RPC="/etc/default/rpc"
STATD_PORT=32766
LOCKD_PORT=32768

RC_NFSD="/etc/rc.d/rc.nfsd"
MOUNTD_PORT=32767

nfs_config() (
	set -euo pipefail
	sed -i '
	s/^#RPC_STATD_PORT=.*/RPC_STATD_PORT='$STATD_PORT'/;
	s/^#LOCKD_TCP_PORT=.*/LOCKD_TCP_PORT='$LOCKD_PORT'/;
	s/^#LOCKD_UDP_PORT=.*/LOCKD_UDP_PORT='$LOCKD_PORT'/;
	' ${DEFAULT_RPC}
	sed -i '
	s/^\s\{4\}\/usr\/sbin\/rpc\.mountd$/    \/usr\/sbin\/rpc\.mountd -p '$MOUNTD_PORT'/;
	' ${RC_NFSD}
	/etc/rc.d/rc.rpc restart
	sleep 1
	/etc/rc.d/rc.nfsd restart
)

nfs_config
if [[ $? -ne 0 ]]; then
	/usr/local/emhttp/webGui/scripts/notify -i warning -s "NFS config failed"
fi

Source: Arch on the unRAID Forums

Analyzing the Script and Creating Our List of Ports to Permit Through the ACL

Analyzing the above script, we see that it takes /etc/default/rpc and uncomments RPC_STATD_PORT, LOCKD_TCP_PORT, and LOCKD_UDP_PORT while setting them equal to 32766, 32768, and 32768 respectively. In /etc/rc.d/rc.nfsd, it passes the the port argument of -p 32767 to /usr/sbin/rpc.mountd. Very nice. So all we need to do is add this script as a user script in unRAID and, now that we have all of our ports identified (111, 2049, 32766-32768), just permit those ports through to the unRAID server in the ACL. We should then be good to go.

NFS Protocols

From the Red Hat article, it says that you’ll need to permit both TCP and UDP for the ports, but it appears that NFS supports both UDP and TCP, so you should only have to pick one protocol (either UDP or TCP) and stick with it. After experimenting, I have decided to go with TCP since UDP really hammers the network when the NFS connection is lost. (Also, I believe, NFSv4 uses TCP only).


Completed (5/15/20):