Environment
- Red Hat Enterprise Linux 7 and 8
- NFS version 3
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
portmap
to 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 - RHEL 8:
/etc/sysconfig/nfs
has been deprecated and replaced by/etc/nfs.conf
in RHEL8. 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 - statd:
STATD_OUTGOING_PORT
can usually be left commented out and defaulting to a random outgoing port, as it's most common to only restrict incoming traffic with a firewall.STATD_OUTGOING_PORT
is only required to be set if the firewall also restricts outgoing traffic.NOTE - RHEL 7 and RHEL 8: After changing anything in
/etc/sysconfig/nfs
(or in/etc/nfs.conf
in RHEL 8) you must runsystemctl restart nfs-server
for the changes to take effect. In RHEL 7,STATD_OUTGOING_PORT
is no longer valid and is replaced bySTATDARG="-o 2020"
.
# systemctl restart nfs-server
NOTE - lockd: If the ports for the
lockd
service can not be changed despite the above setting, you might need to update yournfs-utils
package. This package has a relevant bug in the earlier versions. For more information, please visit our Bugzilla entries Bug 461043.NOTE - protocols: Mount requests without the specific options for
tcp
will 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
- OR if you are using
firewalld
in RHEL 7.x/RHEL 8.x, you would use the following example commands:
# 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