Dim - Continued

Some people have a NAS server (or Nextcloud) on which to store files and movies. However, it might not be possible to compile and run Dim on the same server, and it could also be a good idea to separate the two servers (just in case).

Fortunately, we can share a directory over the network using NFS. NFS is a network filesystem, and is included in the Linux Kernel. There are clients in Windows and MacOS for the protocol, and it's possible to use on Kubernetes and Docker Swarm.

Why it's better to create a Wireguard tunnel?

The problem with NFS is that in it's default configuration, the authorisation system uses a simple IP, and it's very easy to fool/spoof it. Also, it's not encrypted, so it's possible to hack it. But we can create a secure encrypted tunnel using Wireguard, which only permits the machine with the correct public/private key to connect with the NFS directory.

Wireguard is a new and fast VPN protocol, also included in the Linux kernel, and has clients for Android, OpenWRT, MacOS and Windows.

NFS allows the restriction in the access of a network directory to a single IP, and Wireguard allows us to give a specific IP on a distinct subnet to clients which authenticate using secure public/private key cryptography.

Wireguard

The Wireguard tunnel runs on a distinct subnet to the server's IP address. For example, the server can have an IP of 192.168.1.10 but have a distinct IP for Wireguard on another subnet, eg 10.1.0.1.

NFS

For the server/NAS of NFS, which contains the movies

sudo apt install nfs-kernel-server

We have to configure the NFS service to only listen on a single IP (of the Wireguard tunnel). Also, we'll configure it to only use the new protocol NFSv4.

We'll modify the file /etc/default/nfs-kernel-server

nano /etc/default/nfs-kernel-server

And find and add the following lines:

RPCNFSDOPTS="-N 2 -N 3"

to force it to use only the newest version 4 protocol.

RPCMOUNTDOPTS="--manage-gids -N 2 -N 3 -H 10.1.0.1"

to force it to use the tunnel IP.

We'll edit the file /etc/nfs.conf

nano /etc/nfs.conf

And add the following, to make sure the NFS service is only listening on the tunnel IP.

[nfsd] host=10.1.0.1

We have to figure out where the movies are stored.

We modify the exports file (nano /etc/exports) to contain the following:

/the/route/to/the/movies (the client's tunnel IP)/32(rw,sync,no_subtree_check,no_root_squash)

Eg, as I keep my movies on my nextcloud, my configuration is:

/var/cloud/user/movies 10.1.0.2/32(rw,sync,no_subtree_check,no_root_squash)

10.1.0.2/32 is the IP of the client, inside the tunnel

We can export the directory:

sudo exportfs -a

NFSv4 doesn't need some services, so we can deactivate them:

sudo systemctl mask rpcbind.service
sudo systemctl mask rpcbind.socket

Note: In my case, I use Kaspersky Endpoint Security on the server to protect it from malware. The Kaspersky antivirus (KESL) has a feature called anti-cryptor, which monitors the NFS server to prevent a compromised client from deploying ransomware and encrypting all the files on the network share. However, it needs the rpcbind service to function, otherwise it doesn't detect that NFS is running.

and can start the NFS service: sudo systemctl enable --now nfs-kernel-server.service

The Client:

sudo apt install nfs-common

First, we verify that the authentication works. That is, we want to verify that we can't connect to the NFS without using Wireguard. For this, we can check the error that's given when we try to connect a client which is not permitted.

mkdir /mnt/NFS
sudo mount -t nfs -o vers=4.2 (the *normal* IP of the server/NAS):/route/to/movies /mnt/NFS

If everything works correctly, we want an error like: mount.nfs: Operación not permitted or mount.nfs: access denied...

Wireguard

Installing Wireguard on the server and client (run on both):

sudo apt install wireguard
sudo modprobe wireguard

Generate the keys:

cd /etc/wireguard
umask 077
wg genkey > claveprivada
wg pubkey < claveprivada > clavepublica

Server

We create and modify the archive for wireguard: nano /etc/wireguard/wgNFS.conf

Note, that you can choose the subnet and tunnel IP arbitrarily. We can use for example something like 10.1.0.0/24 range and add the following:

[Interface]
Address = 10.1.0.1/24 #the *tunnel* IP of the servidor/NAS
ListenPort = 51820
PrivateKey = THE_PRIVATE_KEY_OF_THE_SERVER

# client1
[Peer]
PublicKey = THE_PUBLIC_KEY_OF_THE_CLIENT
AllowedIPs = 10.1.0.2/32 #The tunnel IP of the client (chosen arbitrarily)

We can find out the public and private keys using: cat claveprivada and cat clavepublica

Client

As above, we create and modify the Wireguard file: nano /etc/wireguard/wgNFS.conf

and add the following:

[Interface]
Address = 10.1.0.2/24
PrivateKey = PRIVATE_KEY_OF_THE_CLIENT

[Peer]
PublicKey = PUBLIC_KEY_OF_THE_SERVER
Endpoint = the real IP of the server:51820
AllowedIPs = 10.1.0.0/24

We can start the Wireguard tunnel using: sudo wg-quick up wgNFS on the server, and later the same on the client.

If everything works, we can check using: ping 10.1.0.1 and ping 10.1.0.2

Mount the folder through Wireguard

On the client we can again try to run sudo mount -t nfs -o vers=4.2 (the *tunnel* IP of the server/NAS):/route/to/movies /mnt/NFS

and this time it should work. We can see the files on the client using ls /mnt/NFS

Making it permanent:

for those using systemd, you can do the following:

# start it automatically when the system starts
sudo systemctl enable wg-quick@wgNFS.service
sudo systemctl daemon-reload

# stop wireguard
sudo wg-quick down wgNFS

# start wireguard using systemd
sudo systemctl start wg-quick@wgNFS.service

sudo umount -f /mnt/NFS

We edit fstab to mount it automatically, and add the following:

10.1.0.1:/route/to/movies   /a/folder/on/the/client    nfs vers=4.2,_netdev,noauto,x-systemd.automount,x-systemd.requires=wg-quick@wgNFS.service

and reload the services

sudo systemctl daemon-reload 
sudo systemctl restart remote-fs.target

If everything worked, in /a/folder/on/the/client which we specified above, should be the files from the server.

UFW

If we use a firewall like UFW, we need to allow port 2049, used by NFS: On the server, we can run: sudo ufw allow from (tunnel ip from wireguard) to any port 2049

,

,

,

,

,

Runit

If you use runit:

you can use the following file run to mount the directories:

#!/bin/sh
set -e
exec 2>&1
# Load user defined variables
[ -r conf ] && . ./conf

# Ensure the network manager is running

# If it's running or not in used - rc.local - discover default gateway
if [ -z "$GATEWAY" ]; then
    set -- $(ip route show | grep default)
    GATEWAY="$3"
fi

ping -W 1 -c 1 $GATEWAY > /dev/null 2>&1 || exit 1

# Network is up and running so now mount network filesystems from fstab
mount -a -t "$NETWORK_FS" || exit 1
mount -a -O _netdev || exit 1

# Then wait to behave like the service is up
exec chpst -b netmount sleep 100000

the file conf:

# Configuration for netmount service

NETWORK_FS="nfs4"

and the file stop

#!/bin/sh
# Load user defined variables
[ -r conf ] && . ./conf

# Don't do anything if ./run didn't exit properly
[ "$1" -eq 1 ] && exit 0

# Simply umount network filesystems
umount -a -f -t $NETWORK_FS > /dev/null 2>&1
ret=$?
[ $ret -ne 0 ] && umount -a -f -l -t $NETWORK_FS > /dev/null 2>&1

umount -a -f -O _netdev > /dev/null 2>&1
ret=$?
[ $ret -ne 0 ] && umount -a -f -l -O _netdev > /dev/null 2>&1
#chpst -b netmount pause

for wireguard, i couldn't get the service for runit, so i set it using cron (crontab -e)

@reboot wg-quick up wgNFS