Vai al contenuto

NFS

Generico

Questa guida descrive l'installazione e l'abilitazione della connessione NFS solo sul cliente. Per l'installazione e abilitazione lato server seguire la guida di Digitalocean

Bash
sudo apt update
sudo apt install nfs-common

Creare la cartella:

Bash
sudo mkdir /mnt/nfs-share

Montare la cartella:

Bash
sudo mount -t nfs NAS_IP:/percorso_della_cartella /mnt/nfs-share

Per montare automaticamente la cartella all'avvio del sistema:

Bash
sudo nano /etc/fstab

e inserire al fondo:

Bash
NAS_IP:/percorso_della_cartella /mnt/nfs-share nfs defaults,nofail,timeo=30,retrans=2 0 0

Nota: rispetto alle opzioni defaults semplici, nofail evita che un mount irraggiungibile blocchi il boot del sistema, mentre timeo=30,retrans=2 (timeout di 3 secondi, 2 tentativi) impedisce che un mount NFS di tipo hard resti appeso a tempo indeterminato se il NAS non risponde — cosa che altrimenti può bloccare anche script di avvio e servizi correlati.

Rendere effettive le modifiche riavviando la macchina oppure:

Bash
sudo mount -a

A questo punto la cartella è accessibile solo all'utente root, per consentire l'accesso ad un utente specifico, creare un gruppo ad hoc:

Bash
sudo groupadd nfsusers

infine aggiungere l'utente al gruppo appena creato:

Bash
sudo usermod -aG nfsusers nome_utente

Configurare le autorizzazioni sulla cartella:

Bash
sudo chown :nfsusers /mnt/nfs-share
sudo chmod 775 /mnt/nfs-share

Riavviare il server NFS:

Bash
sudo service nfs-kernel-server restart

Mount tra reti/VLAN separate (es. dietro pfSense)

Se il client NFS e il NAS si trovano su reti diverse separate da un firewall (es. nodo Proxmox su 192.166.1.0/24 e NAS su una VLAN 192.168.110.0/24 dietro pfSense), oltre al mount servono due passaggi preliminari lato rete.

1. Regola firewall

Sul firewall che separa le due reti (es. pfSense), aggiungere una regola sull'interfaccia da cui parte il traffico (tipicamente WAN se il client sta "davanti" al firewall rispetto alla rete di destinazione):

  • Protocollo: TCP/UDP
  • Origine: IP del client (o alias del gruppo di host)
  • Destinazione: IP del NAS
  • Porta destinazione: 2049 (NFSv4 — sufficiente se si forza NFSv4, evita di dover aprire anche 111 per rpcbind/NFSv3)

Il ping (ICMP) non è coperto da questa regola. Per testare la raggiungibilità usare nc -zv NAS_IP 2049 invece di ping, oppure aggiungere una regola ICMP dedicata se serve.

2. Rotta statica sul client

Il client deve sapere di instradare il traffico verso la subnet del NAS attraverso l'IP del firewall sulla rete del client stesso (non l'IP del gateway internet, se diverso).

Verificare quale sia l'IP corretto controllando le rotte già esistenti verso quella subnet (ip route show) o la configurazione WAN del firewall.

Test rapido (non persistente):

Bash
ip route add 192.168.110.0/24 via <IP_FIREWALL_SULLA_RETE_CLIENT> dev vmbr0
ping -c3 NAS_IP        # fallirà se non c'è regola ICMP, è normale
nc -zv NAS_IP 2049      # verifica reale di raggiungibilità

Persistenza tramite file dedicato in /etc/network/interfaces.d/:

Bash
sudo nano /etc/network/interfaces.d/route-vlan-nas
Text Only
up ip route add 192.168.110.0/24 via <IP_FIREWALL_SULLA_RETE_CLIENT> dev vmbr0
down ip route del 192.168.110.0/24 via <IP_FIREWALL_SULLA_RETE_CLIENT> dev vmbr0

Questa rotta va aggiunta anche come safety net dentro lo script di init del mount NFS (vedi sezione "Persistenza del volume al riavvio"), perché la sequenza di avvio dei servizi di rete ($network) non garantisce che le rotte custom in interfaces.d siano già attive nel momento in cui parte il mount, causando mount NFS appesi indefinitamente al boot.


Proxmox - LXC

Per abilitare un volume NFS su un container LXC, è necessario che questo sia in mode privileged, ma per ragioni di sicurezza è consigliato avviarlo in mode unprivileged. Questo però non permetterebbe la lettura dei volumi in NFS.

Per ovviare al problema, si monta il volume NFS direttamente sull'host. Si crea prima il punto di mount e di binding sull'host:

Bash
mkdir -p /mnt/nfs-share && mkdir -p /mnt/bindmounts/nfs-share

Successivamente si monta il volume NFS sull'host:

Bash
mount -t nfs 192.166.1.29:/volume1/MediaDati /mnt/nfs-share

Si fa a questo punto il bind del volume:

Bash
mount --bind /mnt/nfs-share /mnt/bindmounts/nfs-share

Sul file di configurazione del container

Bash
nano /etc/pve/lxc/<ID DEL CONTAINER>.conf

si aggiunge la riga (usare mp0, mp1, ecc. in base ai bind già presenti):

Text Only
mp0: /mnt/bindmounts/nfs-share,mp=/mnt/nfs-share

Riavviando il container, il volume NFS risulterà già montato.

Permessi in container unprivileged

Nei container unprivileged: 1, gli UID/GID sono rimappati con uno shift (tipicamente +100000) rispetto all'host. Se dopo il mount si ottiene Permission denied in lettura dentro il container pur risultando montato correttamente (visibile con df -h), verificare owner e permessi della cartella lato host:

Bash
ls -la /mnt/nfs-share

Se la cartella appartiene a un utente specifico con permessi restrittivi (es. 750), il container non riuscirà ad accedervi. Soluzioni, in ordine di preferenza:

  • Lato NAS: rendere la cartella leggibile (e scrivibile, se serve) da tutti, es. chmod -R 755 (o 775 per scrittura di gruppo) sulla condivisione esportata.
  • Lato NAS: verificare che l'export NFS non abbia il root_squash attivo se serve accesso come root dal client (impostazione tipicamente in Pannello di controllo → Cartelle condivise → permessi NFS del NAS).

Se i file sono di proprietà di nobody:nogroup con permessi 755, la lettura funziona da qualsiasi container senza ulteriori interventi; per la scrittura invece serve che il processo scrivente nel container corrisponda all'owner effettivo o che i permessi siano aperti anche in scrittura.


La sezione precedente spiega come risolvere i permessi per un singolo container.
Se invece più container devono scrivere sulla stessa condivisione, la soluzione migliore è agire sul server NFS con all_squash, come descritto di seguito.

Gestione di più container LXC unprivileged sulla stessa condivisione NFS

Quando più container LXC (es. Transmission, Jellyfin, jDownloader) devono condividere la stessa cartella NFS in scrittura, il problema dei permessi si complica.
Ogni container unprivileged ha i propri UID rimappati con uno shift (tipicamente +100000 rispetto all'host). Se sul server NFS i permessi della cartella sono restrittivi (es. 750), solo il container il cui UID shiftato corrisponde al proprietario potrà scrivere; gli altri avranno Permission denied.
La soluzione più comune e sbagliata è usare chmod 777 sulla cartella condivisa, ma è insicura e poco elegante.

La soluzione corretta è agire sul server NFS, forzando tutti i client a essere mappati a un unico utente locale tramite l'opzione all_squash con anonuid e anongid personalizzati.

Vantaggi

  • Nessuna modifica ai container (possono restare unprivileged con UID diversi).
  • Nessun 777 sulla cartella condivisa (si usano permessi 775 o 770).
  • Tutti i container scrivono sulla stessa condivisione con lo stesso proprietario sul NAS.

Configurazione lato server NFS (es. Terramaster TOS 5.1)

1. Modificare il file /etc/exports via SSH

Sul NAS, connettersi via SSH (es. porta 9222) e aprire il file delle esportazioni NFS:

Bash
vi /etc/exports

Sostituire le righe esistenti per la cartella condivisa con righe che specificano:

  • all_squash → forza tutti gli utenti client (anche root) all'utente anonimo.
  • anonuid=<UID> e anongid=<GID> → indicano l'utente/gruppo locale del NAS a cui mappare i client.

Esempio pratico:
Supponiamo che sul NAS esista un utente momphucker_user_dati con UID 2 e GID 4 (allusers). Si vogliono esportare /Volume1/MediaDati per i tre IP dei client (host Proxmox e due container).

Bash
"/Volume1/MediaDati" 192.166.1.45(rw,async,crossmnt,insecure_locks,sec=sys,all_squash,anonuid=2,anongid=4,no_subtree_check)
"/Volume1/MediaDati" 192.168.110.37(rw,async,crossmnt,insecure_locks,sec=sys,all_squash,anonuid=2,anongid=4,no_subtree_check)
"/Volume1/MediaDati" 192.168.110.36(rw,async,crossmnt,insecure_locks,sec=sys,all_squash,anonuid=2,anongid=4,no_subtree_check)

Nota:
- Le opzioni crossmnt e insecure_locks sono opzionali e dipendono dal NAS.
- Sostituire UID e GID con quelli dell'utente desiderato sul NAS.
- Se il NAS usa un'interfaccia grafica che riscrive /etc/exports, si consiglia di non usare più la GUI per le modifiche NFS, oppure proteggere il file con chattr +i /etc/exports (vedi sotto).

2. Applicare le modifiche
Bash
exportfs -ra

Verificare che le esportazioni siano attive:

Bash
exportfs -v
3. Impostare proprietario e permessi sulla cartella condivisa

Cambiare il proprietario e il gruppo della cartella con l'utente usato in anonuid/anongid:

Bash
chown -R momphucker_user_dati:allusers /Volume1/MediaDati
chmod -R 775 /Volume1/MediaDati

I permessi 775 garantiscono scrittura al proprietario e al gruppo, ma non a tutti (a differenza del 777).

4. Proteggere /etc/exports da modifiche accidentali (opzionale)

Se il NAS riscrive il file all'avvio o tramite GUI, si può renderlo immutabile:

Bash
chattr +i /etc/exports

Per rimuovere il flag in futuro (es. per modifiche manuali):

Bash
chattr -i /etc/exports

Configurazione lato host Proxmox e container

  • Non serve specificare opzioni uid= o gid= nel mount NFS sull'host (né in /etc/fstab né a riga di comando).
    Il mount deve essere "neutro":
Bash
192.166.1.29:/Volume1/MediaDati /mnt/nfs-share nfs defaults,nofail,timeo=30,retrans=2 0 0
  • I container non richiedono modifiche: i loro UID shiftati verranno ignorati dal server NFS grazie a all_squash.

Verifica finale

Dopo aver configurato il server e rimontato la condivisione sui client, provare a creare un file da ciascun container:

Bash
touch /mnt/nfs-share/test.txt

Se il file viene creato senza errori, la configurazione è corretta.
Sul NAS, i file avranno proprietario momphucker_user_dati (o l'utente scelto) e permessi 664 (per i file) o 775 (per le directory), a seconda delle impostazioni di umask del client.

Attenzione

  • Se si usa l'interfaccia grafica del NAS dopo aver modificato /etc/exports, questa potrebbe sovrascrivere il file cancellando le opzioni all_squash e anonuid. Per evitarlo, o si evita la GUI per le impostazioni NFS, o si protegge il file come descritto.
  • Alcuni NAS (es. Terramaster) non permettono di impostare anonuid/anongid personalizzati tramite GUI, ma solo via SSH. La procedura sopra descritta è valida per questi casi.

Importante: i container non devono avere opzioni uid= o gid= nel mount né modifiche interne agli UID. L'unica modifica è sul server NFS.


Persistenza del volume al riavvio

Per assicurarti che il volume NFS venga montato automaticamente al riavvio dell'host, devi aggiungere la configurazione al file /etc/fstab e utilizzare uno script di avvio per gestire il mount e il bind. Ecco i passaggi dettagliati:

1. Aggiungi la configurazione al file /etc/fstab

Questo file è utilizzato dal sistema per montare i file system all'avvio. Aggiungi una riga per il volume NFS e il bind mount.

Modifica /etc/fstab con un editor di testo:

Bash
sudo nano /etc/fstab

Aggiungi la seguente riga per montare il volume NFS:

Bash
192.166.1.29:/volume1/MediaDati /mnt/nfs-share nfs defaults,nofail,timeo=30,retrans=2 0 0

Salva e chiudi il file.

2. Aggiungi la configurazione per il bind mount

Aggiungi uno script di avvio per gestire il bind mount. Crea uno script di init nel percorso /etc/init.d/, ad esempio:

Bash
sudo nano /etc/init.d/mount-nfs-bind

Inserisci il seguente contenuto nello script. Se il NAS si trova su una rete diversa raggiungibile solo tramite rotta statica, includere anche il comando di route come rete di sicurezza (idempotente: non duplica la rotta se già presente):

Bash
#!/bin/bash

### BEGIN INIT INFO
# Provides:          mount-nfs-bind
# Required-Start:    $network $local_fs
# Required-Stop:     $network $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Mount NFS and bind mount
### END INIT INFO

case "$1" in
  start)
    echo "Ensuring static route to NAS network..."
    ip route show | grep -q "192.168.110.0/24" || ip route add 192.168.110.0/24 via 192.166.1.60 dev vmbr0

    echo "Mounting NFS share and binding..."
    mount -a
    mount --bind /mnt/nfs-share /mnt/bindmounts/nfs-share
    ;;
  stop)
    echo "Unmounting NFS share and bind mount..."
    umount /mnt/bindmounts/nfs-share
    umount /mnt/nfs-share
    ;;
  *)
    echo "Usage: $0 {start|stop}"
    exit 1
    ;;
esac

exit 0

Se sono presenti più share NFS/bind mount, replicare le righe mount --bind (start) e umount (stop, in ordine inverso rispetto al mount — prima i bind, poi gli NFS sottostanti) per ciascuna coppia di percorsi.

Salva e chiudi il file. Rendi eseguibile lo script:

Bash
sudo chmod +x /etc/init.d/mount-nfs-bind

3. Abilita lo script di avvio

Aggiungi lo script al sistema di avvio:

Bash
sudo update-rc.d mount-nfs-bind defaults

Verifica della configurazione

Dopo aver configurato tutto, riavvia l'host e verifica se il volume NFS e il bind mount vengono applicati correttamente:

Bash
sudo reboot

Dopo il riavvio, controlla che rotta e mount siano attivi:

Bash
ip route show | grep <SUBNET_NAS>
df -h | grep nfs-share
mount | grep nfs-share

Dovresti vedere il volume NFS montato su /mnt/nfs-share e il bind mount su /mnt/bindmounts/nfs-share.

Infine, verifica anche dall'interno del container LXC che il punto di mount configurato in mpN sia accessibile e leggibile:

Bash
pct enter <ID_CONTAINER>
ls -la /mnt/nfs-share

Con questi passaggi, il volume NFS si monta automaticamente all'avvio (anche attraverso reti/VLAN separate da firewall), il bind mount è configurato per il container LXC, e i timeout impostati evitano che un NAS temporaneamente irraggiungibile blocchi il boot del sistema.