Export directory over local network using NFSv4 to access data on a central server.

Server

Inspect network interfaces.

$ ip --brief addr
lo               UNKNOWN        127.0.0.1/8 ::1/128 
enp0s8           UP             192.168.57.11/24

Install firewalld service.

$ sudo apt install firewalld

Display default zone.

$ sudo firewall-cmd --get-default-zone  
public

Display zone stttings.

$ sudo firewall-cmd --list-all --zone public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces:
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

Add interface to the default zone.

$ sudo firewall-cmd --add-interface enp0s8 --zone public

success

Add NFS service to the default zone.

$ sudo firewall-cmd --add-service nfs --zone public
success

Display zone stttings.

$ sudo firewall-cmd --list-all --zone public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s8
  sources: 
  services: dhcpv6-client nfs ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:

Ensure that configuration is permanent.

$ sudo firewall-cmd --runtime-to-permanent  
success

Inspect service status to ensure that service is enabled at boot.

$ systemctl status firewalld.service 
● firewalld.service - firewalld - dynamic firewall daemon
     Loaded: loaded (/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2023-01-05 14:11:25 UTC; 50min ago
       Docs: man:firewalld(1)
   Main PID: 2676 (firewalld)
      Tasks: 3 (limit: 364)
     Memory: 30.0M
        CPU: 740ms
     CGroup: /system.slice/firewalld.service
             └─2676 /usr/bin/python3 /usr/sbin/firewalld --nofork --nopid

Jan 05 14:11:25 ubuntu-jammy systemd[1]: Starting firewalld - dynamic firewall daemon...
Jan 05 14:11:25 ubuntu-jammy systemd[1]: Started firewalld - dynamic firewall daemon

Create directory that will be shared to the remote server.

$ sudo install --owner www-data --group www-data --directory /srv/exports/www

Install NFS kernel server with supporting applications.

$ sudo apt install nfs-kernel-server nfs-common

Inspect service status.

$ systemctl status nfs-kernel-server.service 
● nfs-server.service - NFS server and services
     Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; vendor preset: enabled)
     Active: active (exited) since Thu 2023-01-05 15:23:11 UTC; 17min ago
   Main PID: 3887 (code=exited, status=0/SUCCESS)
        CPU: 5ms

Inspect service configuration.

$ cat /etc/nfs.conf
#        
# This is a general configuration for the
# NFS daemons and tools
#       
[general]      
pipefs-directory=/run/rpc_pipefs
#      
[exports]
# rootdir=/export
#        
[exportfs]
# debug=0  
#          
[gssd]     
# verbosity=0
# rpc-verbosity=0
# use-memcache=0
# use-machine-creds=1
# use-gss-proxy=0
# avoid-dns=1
# limit-to-legacy-enctypes=0
# context-timeout=0
# rpc-timeout=5                          
# keytab-file=/etc/krb5.keytab
# cred-cache-directory=
# preferred-realm=
#          
[lockd]  
# port=0 
# udp-port=0    
#               
[mountd]        
# debug=0     
manage-gids=y
# descriptors=0
# port=0    
# threads=1                                                                                                                                                                                                 
# reverse-lookup=n
# state-directory-path=/var/lib/nfs
# ha-callout=
#
[nfsdcld]
# debug=0
# storagedir=/var/lib/nfs/nfsdcld
#
[nfsdcltrack]
# debug=0
# storagedir=/var/lib/nfs/nfsdcltrack
#
[nfsd]
# debug=0
# threads=8
# host=
# port=0
# grace-time=90
# lease-time=90
# udp=n
# tcp=y
# vers2=n
# vers3=y
# vers4=y
# vers4.0=y
# vers4.1=y
# vers4.2=y
# rdma=n
# rdma-port=20049
#
[statd]
# debug=0
# port=0
# outgoing-port=0
# name=
# state-directory-path=/var/lib/nfs/statd
# ha-callout=
# no-notify=0
#
[sm-notify]
# debug=0
# force=0
# retry-time=900
# outgoing-port=
# outgoing-addr=
# lift-grace=y
#
[svcgssd]
# principal=

Create minimal configuration for NFSv4.

$ sudo tee /etc/nfs.conf <<EOF
#        
# This is a general configuration for the
# NFS daemons and tools
#       
[general]      
pipefs-directory=/run/rpc_pipefs
[exports]
rootdir=/srv/exports
[nfsd]
threads=4
udp=n
tcp=y
vers2=n
vers3=n
vers4=y
vers4.0=y
vers4.1=y
vers4.2=y
EOF
#        
# This is a general configuration for the
# NFS daemons and tools
#       
[general]      
pipefs-directory=/run/rpc_pipefs
[exports]
rootdir=/srv/exports
[nfsd]
threads=4
udp=n
tcp=y
vers2=n
vers3=n
vers4=y
vers4.0=y
vers4.1=y
vers4.2=y

Restart service.

$ sudo systemctl restart nfs-kernel-server

Specify exported directory and define user/group ID.

$ cat << EOF | sudo tee -a /etc/exports
/www 192.168.57.1(rw,sync,anonuid=33,anongid=33,no_subtree_check) 192.168.57.10(ro,no_subtree_check)
EOF

Export defined directories.

$ sudo exportfs -r -a -v
exporting 192.168.57.1:/www
exporting 192.168.57.10:/www

Display current export list including export options to verify configuration.

$ sudo exportfs -v
/www            192.168.57.1(sync,wdelay,hide,no_subtree_check,anonuid=33,anongid=33,sec=sys,rw,secure,root_squash,no_all_squash)
/www            192.168.57.10(sync,wdelay,hide,no_subtree_check,sec=sys,ro,secure,root_squash,no_all_squash)

Client

Install NFS support programs.

$ sudo apt install nfs-common

Create directory.

$ sudo install --owner www-data --group www-data --directory /var/www

Mount NFS export.

$ sudo mount -t nfs4 -o rw 192.168.57.10:/www /var/www

Display mounted NFS exports.

$ mount -t nfs4
192.168.57.10:/www on /var/www type nfs4 (rw,relatime,vers=4.2,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.57.1,local_lock=none,addr=192.168.57.10)

Escape path that will be used as mount name.

$ systemd-escape --path var/www
var-www

Ensure that it will mount at boot.

$ sudo tee /etc/systemd/system/var-www.mount <<EOF
[Unit]
Description=Mount NFS share
After=network-online.target
Wants=network-online.target

[Mount]
What=192.168.57.10:/www
Where=/var/www
Options=rw,auto
Type=nfs
TimeoutSec=60

[Install]
WantedBy=remote-fs.target
EOF
[Unit]
Description=Mount NFS share
After=network-online.target
Wants=network-online.target

[Mount]
What=192.168.57.10:/www
Where=/var/www
Options=rw,auto
Type=nfs
TimeoutSec=60

[Install]
WantedBy=remote-fs.target

Reload systemd configuration.

$ sudo systemctl daemon-reload

Mount NFS share and enable it at boot.

$ sudo systemctl enable --now var-www.mount 
Created symlink /etc/systemd/system/remote-fs.target.wants/var-www.mount → /etc/systemd/system/var-www.mount.

Additional information

This blog post was updated on 8 January 2023.