How to configure a system as an NFSv3 server which sits behind a firewall with NFS clients outside of the firewall?
Environment
- Red Hat Enterprise Linux 9
- Red Hat Enterprise Linux 8
- Red Hat Enterprise Linux 7
- NFS v3
Issue
- Cannot connect to my NFS server which sits behind a firewall.
- How to assign permanent ports to NFS services?
- How to bind RPC services, which are related to NFS, to a static port?
Resolution
-
NFSv3 and below rely on
portmapto assign the ports on which it will listen. One side effect of this is that the ports are randomly assigned, so each time NFS is restarted the ports will change. This can make it difficult to run an NFS server behind a firewall which only allows access to specific ports on the system. -
The first step is to assign a permanent port number to each of the NFS services (
rquotad,mountd,statd, andlockd). You may use your own custom port numbers, although there are SELinux rules which prevent some of these services from starting on non-default ports. We strongly recommend using the default ports. The following examples use the default port numbers. -
The port numbers for these services are configured through the file
/etc/sysconfig/nfs. You will need to create this file if it does not exist. It should look similar to the following example:# Port rquotad should listen on. RQUOTAD_PORT=875 # TCP port rpc.lockd should listen on. LOCKD_TCPPORT=32803 # UDP port rpc.lockd should listen on. LOCKD_UDPPORT=32769 # Port rpc.mountd should listen on. MOUNTD_PORT=892 # Port rpc.statd should listen on. STATD_PORT=662 # Outgoing port statd should used. The default is port # is random #STATD_OUTGOING_PORT=2020-
Note that
/etc/sysconfig/nfshas been deprecated and replaced by/etc/nfs.confin RHEL8 and later. In this example, the following ports would have to be configured at minimum:[lockd] port=32803 udp-port=32769 [mountd] port=892 [statd] port=662
-
Note that
STATD_OUTGOING_PORTcan usually be left commented out and defaulting to a random outgoing port, as it's most common to only restrictstatdincoming traffic with a firewall.STATD_OUTGOING_PORTis only required to be set if the firewall also restricts outgoing traffic. -
After changing anything in
/etc/sysconfig/nfs(or in/etc/nfs.confin RHEL 8) you must runsystemctl restart rpc-statdand thensystemctl restart nfs-server, ensuring thisorderis followed, for the changes to take effect. In RHEL 7,STATD_OUTGOING_PORTis no longer valid and is replaced bySTATDARG="-o 2020".# systemctl restart rpc-statd # systemctl restart nfs-server -
If the ports for the
lockdservice can not be changed despite the above setting, you might need to update yournfs-utilspackage. This package has a relevant bug in the earlier versions. -
Mount requests without the specific options for
tcpwill default toudp. -
After these configuration changes, you can view the port assignments with the command
rpcinfo -p <hostname>:# rpcinfo -p localhost program vers proto port 100000 2 tcp 111 portmapper 100000 2 udp 111 portmapper 100024 1 udp 662 status 100024 1 tcp 662 status 100011 1 udp 875 rquotad 100011 2 udp 875 rquotad 100011 1 tcp 875 rquotad 100011 2 tcp 875 rquotad 100003 2 udp 2049 nfs 100003 3 udp 2049 nfs 100003 4 udp 2049 nfs 100021 1 udp 32769 nlockmgr 100021 3 udp 32769 nlockmgr 100021 4 udp 32769 nlockmgr 100021 1 tcp 32803 nlockmgr 100021 3 tcp 32803 nlockmgr 100021 4 tcp 32803 nlockmgr 100003 2 tcp 2049 nfs 100003 3 tcp 2049 nfs 100003 4 tcp 2049 nfs 100005 1 udp 892 mountd 100005 1 tcp 892 mountd 100005 2 udp 892 mountd 100005 2 tcp 892 mountd 100005 3 udp 892 mountd 100005 3 tcp 892 mountd
-
-
At this point, the ports will remain the same when NFS is restarted. The following is a list of ports which need to be opened on the firewall:
- 111: portmap (tcp/udp)
- 2049: nfs (tcp/udp)
- 875: example rquotad (tcp/udp)
- 32803: lockd (tcp)
- 32769: lockd (udp)
- 892: mountd (tcp/udp)
- 662: statd/status (tcp/udp)
- 2020: statd/status outgoing (tcp/udp) - optional as per note above
-
You can now open these ports on the firewall to allow remote clients to mount a share on the server. If you are using
iptables, the following commands can be used to add inbound/outbound rules to allow access to these ports. Note that this is only an example, as your specific firewall rules may differ:iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p icmp -j ACCEPT iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -m comment --comment "sshd" -j ACCEPT iptables -A INPUT -p tcp --dport 111 -m comment --comment "portmap" -j ACCEPT iptables -A INPUT -p udp --dport 111 -m comment --comment "portmap" -j ACCEPT iptables -A INPUT -p tcp --dport 2049 -m comment --comment "nfs" -j ACCEPT iptables -A INPUT -p udp --dport 2049 -m comment --comment "nfs" -j ACCEPT iptables -A INPUT -p tcp --dport 875 -m comment --comment "rquotad" -j ACCEPT iptables -A INPUT -p udp --dport 875 -m comment --comment "rquotad" -j ACCEPT iptables -A INPUT -p tcp --dport 32803 -m comment --comment "lockd" -j ACCEPT iptables -A INPUT -p udp --dport 32769 -m comment --comment "lockd" -j ACCEPT iptables -A INPUT -p tcp --dport 892 -m comment --comment "mountd" -j ACCEPT iptables -A INPUT -p udp --dport 892 -m comment --comment "mountd" -j ACCEPT iptables -A INPUT -p tcp --dport 662 -m comment --comment "statd" -j ACCEPT iptables -A INPUT -p udp --dport 662 -m comment --comment "statd" -j ACCEPT iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited -
If your firewall restricts outgoing traffic:
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A OUTPUT -p icmp -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT iptables -A OUTPUT -p tcp -m state --state NEW -m tcp --dport 22 -m comment --comment "ssh-client" -j ACCEPT iptables -A OUTPUT -p tcp --sport 111 -m comment --comment "portmap" -j ACCEPT iptables -A OUTPUT -p udp --sport 111 -m comment --comment "portmap" -j ACCEPT iptables -A OUTPUT -p tcp --sport 2049 -m comment --comment "nfs" -j ACCEPT iptables -A OUTPUT -p udp --sport 2049 -m comment --comment "nfs" -j ACCEPT iptables -A OUTPUT -p tcp --sport 875 -m comment --comment "rquotad" -j ACCEPT iptables -A OUTPUT -p udp --sport 875 -m comment --comment "rquotad" -j ACCEPT iptables -A OUTPUT -p tcp --sport 32803 -m comment --comment "lockd" -j ACCEPT iptables -A OUTPUT -p udp --sport 32769 -m comment --comment "lockd" -j ACCEPT iptables -A OUTPUT -p tcp --sport 892 -m comment --comment "mountd" -j ACCEPT iptables -A OUTPUT -p udp --sport 892 -m comment --comment "mountd" -j ACCEPT iptables -A OUTPUT -p tcp --sport 662 -m comment --comment "statd" -j ACCEPT iptables -A OUTPUT -p udp --sport 662 -m comment --comment "statd" -j ACCEPT iptables -A OUTPUT -p tcp --sport 2020 -m comment --comment "statd" -j ACCEPT iptables -A OUTPUT -p udp --sport 2020 -m comment --comment "statd" -j ACCEPT iptables -A OUTPUT -j REJECT --reject-with icmp-port-unreachable -
Optionally, if you are using
firewalldin RHEL7 or later, you can use followingfirewalldcommands:# firewall-cmd --permanent --add-port=111/tcp # firewall-cmd --permanent --add-port=111/udp # firewall-cmd --permanent --add-port=2049/tcp # firewall-cmd --permanent --add-port=2049/udp # firewall-cmd --permanent --add-port=875/udp # firewall-cmd --permanent --add-port=875/tcp # firewall-cmd --permanent --add-port=32803/tcp # firewall-cmd --permanent --add-port=32769/udp # firewall-cmd --permanent --add-port=892/tcp # firewall-cmd --permanent --add-port=892/udp # firewall-cmd --permanent --add-port=662/tcp # firewall-cmd --permanent --add-port=662/udp # firewall-cmd --reload
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.