.

Writing mostly about computers and math.

📅 

I reconfigured the firewall on my server this weekend and I had some trouble getting NFS to work right so I decided to document my process here in case I ever have to do it again. I think the configuration files will be in the same place on all Debian-based distros but I didn't check since I've still got Ubuntu 16.04 on my file server.

The firewall is currently configured to allow all outgoing traffic (need to fix that) but the incoming traffic is filtered by port and source IP. Basically, I have it set up so that only SSH and HTTP(S) are allowed from WAN but lots of services are accessible from the LAN. For NFS, the ports we care about are:

  • 111
  • 2049
  • Wherever mountd and nlockmgr decide to listen

That last one is really what I was having trouble with. I tried to mount the exported directory and the command would just hang for a long time and then fail. Same thing for rpcinfo. I figured the firewall was blocking NFS so I added rules for the first two ports but wasn't sure what to do about mountd and nlockmgr. If a service doesn't listen on a fixed port, it's pretty much impossible to write an iptables rule for it so I had to set a fixed port for each service.

To tell mountd what port we want it to use, we have to modify /etc/defaults/nfs-kernel-server. This file is different on other distros but for Ubuntu (and I think all Debian-based distros) that's the file we want. By default, it looks something like this:


# Number of servers to start up
RPCNFSDCOUNT=8

# Runtime priority of server (see nice(1))
RPCNFSDPRIORITY=0

# Options for rpc.mountd.
# If you have a port-based firewall, you might want to set up
# a fixed port here using the --port option. For more information,
# see rpc.mountd(8) or http://wiki.debian.org/SecuringNFS
# To disable NFSv4 on the server, specify '--no-nfs-version 4' here
RPCMOUNTDOPTS="--manage-gids"

# Do you want to start the svcgssd daemon? It is only required for Kerberos
# exports. Valid alternatives are "yes" and "no"; the default is "no".
NEED_SVCGSSD=""

# Options for rpc.svcgssd.
RPCSVCGSSDOPTS=""

# Options for rpc.nfsd.
RPCNFSDOPTS=""

The config file is nice enough to tell us what to do: to get mountd to listen on a particular port, we need to change RPCMOUNTDOPTS to include -p <port>. I picked port 2000 since I didn't need it for anything else so I ended up with RPCMOUNTDOPTS="--manage-gids -p 2000"

Easy. nlockmgr is a little more complicated since it's part of a kernel module. Fortunately, systemd provides a way to reconfigure this module without restarting the system. If you create a file in /etc/sysctl.d/ then the options can go in there and systemd will apply them for you. I called my file 30-nfs-ports.conf (the files run in order) but you can use whatever name you want. Here's what it looks like:

fs.nfs.nlm_tcpport = 2001
fs.nfs.nlm_udpport = 2002

That sets nlockmgr to listen on ports 2001 (TCP) and 2002 (UDP). To apply the settings we just do sysctl --system and it loads our new config file. Now all that's left to do is poke the requisite holes in the firewall.

I'll assume you already pretty much know how to interact with iptables and don't need me to explain all of the options I'm using here. Basically, I just want these ports to be open to the LAN so I only allow connections from that subnet. Once again, the ports I need to open are 111, 2000, 2001 (TCP only), 2002 (UDP only), and 2049. You might want to change the IPs to fit your network but here's what I used:

iptables -A INPUT -s 192.168.0.0/16 -p tcp -m multiport --ports 111,2000,2001,2049 -j ACCEPT
iptables -A INPUT -s 192.168.0.0/16 -p udp -m multiport --ports 111,2000,2002,2049 -j ACCEPT

Now if we restart NFS and run rpcinfo on the client, we can see the open ports on the server:


$ sudo rpcinfo -p server
   program vers proto   port  service
    100000    4   tcp    111  portmapper
    100000    3   tcp    111  portmapper
    100000    2   tcp    111  portmapper
    100000    4   udp    111  portmapper
    100000    3   udp    111  portmapper
    100000    2   udp    111  portmapper
    100005    3   udp   2000  mountd
    100005    3   tcp   2000  mountd
    100003    2   tcp   2049  nfs
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    2   tcp   2049
    100227    3   tcp   2049
    100003    2   udp   2049  nfs
    100003    3   udp   2049  nfs
    100003    4   udp   2049  nfs
    100227    2   udp   2049
    100227    3   udp   2049
    100021    1   udp   2002  nlockmgr
    100021    3   udp   2002  nlockmgr
    100021    4   udp   2002  nlockmgr
    100021    1   tcp   2001  nlockmgr
    100021    3   tcp   2001  nlockmgr
    100021    4   tcp   2001  nlockmgr

That's it; the server is now accessible from the LAN on the ports we need for NFS. This was enough to get things to mount on the machines that use this server which is really all I wanted to get done this weekend. I'll probably play with it some more in the future so there may be more iptables-related posts in the future.