How to configure a system as an NFSv3 server which sits behind a firewall with NFS clients outside of the firewall?

Solution Verified - Updated

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 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, and lockd). 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/nfs has been deprecated and replaced by /etc/nfs.conf in 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_PORT can usually be left commented out and defaulting to a random outgoing port, as it's most common to only restrict statd incoming traffic with a firewall. STATD_OUTGOING_PORT is only required to be set if the firewall also restricts outgoing traffic.

    • After changing anything in /etc/sysconfig/nfs (or in /etc/nfs.conf in RHEL 8) you must run systemctl restart rpc-statd and thensystemctl restart nfs-server, ensuring this order is followed, for the changes to take effect. In RHEL 7, STATD_OUTGOING_PORT is no longer valid and is replaced by STATDARG="-o 2020".

      # systemctl restart rpc-statd
      # systemctl restart nfs-server
      
    • If the ports for the lockd service can not be changed despite the above setting, you might need to update your nfs-utils package. This package has a relevant bug in the earlier versions.

    • Mount requests without the specific options for tcp will default to udp.

    • 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 firewalld in RHEL7 or later, you can use following firewalld 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
    
Components
Category

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.