In this post, I'll explain how to securely configure NFS on Debian, to mount a directory from one server on another machine. A good use case for this is if you have a storage VPS with a large amount of storage, and want to use this space from other servers.
NFS is unencrypted by default. It can be encrypted if you use Kerberos, but I wouldn't recommend going through the pain of configuring Kerberos unless you're setting up a corporate network with dozens of users.
Because of this, I would recommend never exposing an NFS server directly to the internet. I'd also advise against exposing it on "internal" networks which are not isolated per customer, such as what HostHatch provides. On isolated private networks (like what BuyVM provides), it's fine to use NFS unecrypted.
To secure NFS connections over the internet or other untrusted network, I'd recommend using WireGuard. There are various guides on how to configure WireGuard (like this one) so I won't go into it in too much detail. Note that WireGuard does not have the concept of a "client" and "server" like classic VPN solutions like OpenVPN. Each node is a "peer", and the overall topology is up to you. For example, you can have a "mesh" VPN network where every machine can directly access every other machine, without a central server.
On Debian 11 (Bullseye, testing) you can simply use apt install wireguard to get WireGuard. On Debian 10 (Buster), you'll have to enable buster-backports then do apt -t buster-backports install wireguard.
Generate a private and public key on each system:
wg genkey | tee privatekey | wg pubkey > publickey
Then configure /etc/wireguard/wg0.conf on each system. The [Interface] section should have the private key for that particular system. The NFS server should have a [Peer] section for each system that is allowed to access the NFS server, and all the other systems should have a [Peer] section for the NFS server. It should look something like this:
[Interface] Address = 10.123.0.2 PrivateKey = 12345678912345678912345678912345678912345678 ListenPort = 51820 [Peer] PublicKey = 987654321987654321987654321987654321987654321 AllowedIPs = 10.123.0.1/32 Endpoint = 198.51.100.1:51820
10.123.0.2 can be any IPs of your choosing, as long as they're in the same subnet and in one of the IP ranges reserved for local networks (10.x.x.x is usually a good choice).
Enable and start the WireGuard service on each machine:
systemctl enable wg-quick@wg0 systemctl start wg-quick@wg0
wg to check that it's running. Make sure you can
ping the NFS server from the other servers.
On the NFS server, install the
apt install nfs-kernel-server
A best practice these days is to only enable NFSv4 unless you really need NFSv3. To only enable NFSv4, set the following variables in
And the following in
/etc/default/nfs-kernel-server. Note that
RPCNFSDOPTS is not present by default, and needs to be added.
RPCNFSDOPTS="-N 2 -N 3 -H 10.123.0.1" RPCMOUNTDOPTS="--manage-gids -N 2 -N 3"
10.123.0.1 should be the IP address the NFS server will listen on (the WireGuard IP).
Additionally, rpcbind is not needed by NFSv4 but will be started as a prerequisite by nfs-server.service. This can be prevented by masking rpcbind.service and rpcbind.socket:
systemctl mask rpcbind.service systemctl mask rpcbind.socket
Next, configure your NFS exports in
/etc/exports. For example, this will export the
/data/hello-world directory and only allow
10.123.0.2 to access it:
Refer to the exports(5) man page for more details.
Finally, start the NFS server:
systemctl start nfs-server
On the NFS client, you need to install the
apt install nfs-common
Now, you can use the
mount command to mount the directory over NFS:
mkdir -p /mnt/data/ mount -t nfs4 -o vers=4.2,async 10.123.0.1:/data/hello-world /mnt/data/
Try write some files to
/mnt/data, and it should work!
To automatically mount the directory on boot, modify
10.123.0.1:/data/hello-world /mnt/data nfs4 auto,vers=4.2
You can optionally cache data from the NFS server on the local disk by using a transparent read-through cache called
CacheFS. The first time files are read via NFS, they will be cached locally. On subsequent reads, if the file has not been modified since the time it was cached, it will be read from the local cache rather than loading over the network. This can provide a significant performance benefit if the NFS server has slower disks and/or is physically distant from the clients.
To enable caching, first install
apt install cachefilesd
Turn it on by editing
/etc/default/cachefilesd, following the instructions in the file:
# You must uncomment the run=yes line below for cachefilesd to start. # Before doing so, please read /usr/share/doc/cachefilesd/howto.txt.gz as # extended user attributes need to be enabled on the cache filesystem. RUN=yes
Modify your NFS mount in
/etc/fstab to add the
fsc (file system cache) attribute. For example:
10.123.0.1:/data/hello-world /mnt/data nfs4 auto,vers=4.2,fsc
Finally, start the service and remount your directory:
systemctl start cachefilesd mount -o remount /mnt/data
To check that it's working, read some files from the mount, and you should see
/var/cache/fscache/ growing in size:
du -sh /var/cache/fscache/ 76K /var/cache/fscache/
By default, the cache will keep filling up until the disk only has 7% space left. Once the disk drops below 7% free space. If the disk space drops below 3%, caching will be turned off entirely. You can change these thresholds by modifying