SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor

Nano non salva: risolvere "Permission denied"

Nano mostra "Permission denied" al salvataggio? Controlla proprietario, directory padre, filesystem in sola lettura o pieno e uid del container.

Perché nano non salva il file

nano non salva il file per uno di quattro motivi: non sei il proprietario del file, la directory padre non consente l'operazione che nano sta tentando di eseguire, il filesystem è di sola lettura o non ha spazio disponibile, oppure ti trovi all'interno di un container in esecuzione con un ID utente diverso. I primi due sono problemi di autorizzazioni, gli ultimi due no. Verificali in questo ordine, perché il primo motivo copre la maggior parte dei casi, si conferma con un solo comando e la relativa correzione è sudoedit anziché sudo nano.

Finché l'editor è aperto, non perdi nulla. Il testo resta in memoria. Puoi lasciare il file aperto, scrivere il buffer in un percorso di cui sei proprietario e sostituire il file originale in un secondo momento. Questa soluzione alternativa è descritta verso la fine della guida.

Esegui questi controlli prima di modificare i permessi

Indica a ogni comando il percorso reale che stai modificando. I comandi rispondono a domande diverse, quindi eseguili tutti prima di intervenire. Modificare i permessi prima di sapere quale controllo fallisce spesso crea un secondo problema oltre al primo.

id
ls -l /etc/nginx/nginx.conf
ls -ld /etc/nginx
namei -l /etc/nginx/nginx.conf
findmnt -no SOURCE,FSTYPE,OPTIONS -T /etc/nginx/nginx.conf
df -h /etc/nginx
df -i /etc/nginx

id stampa l'ID utente e gli ID dei gruppi associati alla sessione corrente. ls -l mostra il proprietario, il gruppo e i bit dei permessi del file stesso. ls -ld mostra gli stessi dati per la directory che lo contiene; è una verifica distinta, con una risposta distinta. namei -l analizza ogni componente del percorso ed elenca il proprietario e i permessi di ciascuno, quindi risponde a entrambe le domande in un unico output. findmnt identifica il filesystem associato al percorso e le opzioni con cui è stato montato. df -h riporta lo spazio libero e df -i riporta gli inode disponibili, che possono esaurirsi indipendentemente dallo spazio. Se queste stringhe dei permessi non ti sono ancora familiari, inizia da come leggere la stringa dei permessi stampata da ls -l.

Causa 1: il file appartiene a root e il tuo account no

I permessi di lettura e scrittura sono distinti e la maggior parte dei file in /etc è leggibile da tutti. Per questo nano apre il file, ne mostra il contenuto e consente di digitare liberamente: nessuna di queste operazioni modifica il disco. Il rifiuto avviene al momento del salvataggio, quando il kernel confronta l'ID utente e gli ID dei gruppi con il proprietario, il gruppo e i bit relativi agli altri utenti del file. nano riporta ciò che gli comunica il kernel, quindi nessuna opzione di nano può modificare il risultato.

id e ls -l lo confermano. Il file appartiene a root, il tuo account non è root e i bit relativi agli altri utenti non concedono il permesso di scrittura. Premere di nuovo Ctrl-O non risolverà il problema.

Perché sudoedit è il modo corretto per modificare un file di proprietà di root

SUDO_EDITOR=nano sudoedit /etc/nginx/nginx.conf

sudo crea una copia temporanea del file, impostandone il proprietario sull'utente corrente, avvia nano su quella copia con i privilegi dell'utente corrente, quindi copia il risultato nella posizione originale con i privilegi di root quando l'editor termina. L'editor non viene mai eseguito come root. sudo -e è lo stesso comando con un nome diverso. L'editor viene scelto prima da SUDO_EDITOR, poi da VISUAL e infine da EDITOR, quindi impostare export EDITOR=nano nel profilo della shell rende questa scelta predefinita ovunque. Se nessuna di queste variabili specifica un editor esistente ed eseguibile, sudoedit usa l'impostazione editor in sudoers, che per impostazione predefinita è vi.

sudo nano salva anch'esso il file, e questo è il problema. Concede a un editor interattivo completo i privilegi di root sull'intero filesystem per tutta la durata della sessione. Di conseguenza, un percorso digitato erroneamente al prompt di salvataggio può sovrascrivere un altro file di sistema con i privilegi di root. Lavorare come utente normale e usare sudo solo per i passaggi che richiedono quei privilegi è l'abitudine da sviluppare, e sudoedit è l'applicazione di questa abitudine quando si modifica un file di configurazione.

Due regole di sudoedit sorprendono molti utenti. Il comando rifiuta di modificare un collegamento simbolico e rifiuta di modificare un file contenuto in una directory in cui l'utente può scrivere, a meno che l'utente non sia root. La seconda regola esiste perché chiunque possa scrivere nella directory può sostituire il file mentre l'editor è aperto. Entrambi i comportamenti sono le impostazioni predefinite di sudoers (sudoedit_follow disattivato, sudoedit_checkdir attivato). Se il file non esiste ancora, viene creato.

Causa 2: che cosa controlla realmente la directory padre

Le indicazioni scritte per altri editor spiegano che per salvare serve il permesso di scrittura sulla directory, perché molti editor salvano scrivendo un nuovo file e rinominandolo in modo da sostituire quello precedente. nano non funziona in questo modo. Apre il file specificato e scrive direttamente al suo interno. Per un file già esistente, quindi, il bit di scrittura della directory non viene mai verificato.

La directory continua a determinare altri aspetti. Per questo ls -ld è incluso nell'elenco dei controlli:

  • La creazione di un file che non esiste ancora richiede i permessi di scrittura ed esecuzione sulla directory, perché è necessario aggiungere un nuovo nome. Il tuo umask determina i permessi iniziali del nuovo file.
  • Per raggiungere il file servono i permessi di esecuzione, chiamati anche permessi di ricerca, su ogni directory lungo il percorso. Se manca questo permesso in una directory, tutto ciò che si trova al suo interno diventa inaccessibile; namei -l mostra quale directory è coinvolta.
  • Il salvataggio con i backup o con il blocco dei file attivato scrive un secondo file accanto all'originale. Queste funzioni richiedono quindi una directory scrivibile. I backup sono l'opzione -B o set backup in un nanorc; il blocco è -G o set locking. Entrambe le funzioni sono disattivate, a meno che tu o la tua distribuzione non le abbiate attivate.

I permessi delle directory hanno la stessa importanza anche in altre parti del sistema. Il server SSH rifiuta una chiave quando la directory home o la directory .ssh può essere modificata da altri utenti. Questa è una causa comune del rifiuto della chiave SSH durante l'accesso.

Poiché nano scrive nel file già esistente, il file conserva il proprio inode, cioè l'identità del file sul disco associata al nome. Qualsiasi processo che mantiene aperto il file continua a seguirlo, e un singolo file bind mounted in un container continua a funzionare. Gli editor che salvano sostituendo il file interrompono questo mount, perché il mount segue l'inode e non il nome.

Causa 3: il filesystem è in sola lettura oppure non ha più spazio disponibile

findmnt ro nelle opzioni indica che la scrittura non sarebbe mai riuscita. Il filesystem potrebbe essere stato montato in quel modo, tramite /etc/fstab o con un bind mount in sola lettura, oppure il kernel potrebbe averlo rimontato in sola lettura dopo un errore del disco. Il secondo caso è quello grave. sudo dmesg -T | tail -50 mostra i messaggi più recenti del kernel, ma gli errori di input/output e del filesystem che hanno causato il rimontaggio potrebbero non trovarsi tra le ultime 50 righe. Esegui sudo dmesg -T senza tail per visualizzare tutti i messaggi ancora presenti nel buffer circolare del kernel e cerca gli errori registrati prima del rimontaggio. La correzione consiste nell'eseguire un controllo del filesystem quando il filesystem non è montato. Un filesystem diverso da root può essere smontato e controllato direttamente. Per root, può occuparsene un avvio normale: systemd controlla ogni filesystem il cui numero di passaggio fsck in /etc/fstab è maggiore di zero, controlla root nell'initrd quando l'initrd lo supporta e fsck.mode=force nella riga di comando del kernel forza un controllo completo. Se il VPS non si avvia abbastanza da consentirlo, la console di ripristino del provider è l'alternativa.

Un filesystem pieno impedisce la stessa scrittura per un motivo diverso. df -h copre il caso ordinario. df -i copre il caso che spesso viene trascurato: su ext4, il valore predefinito più comune, gli inode provengono da un pool fisso creato quando il filesystem è stato creato e un albero di file di piccole dimensioni può usarli tutti mentre df -h mostra ancora gigabyte liberi. XFS alloca gli inode quando vengono creati i file, quindi questo caso riguarda soprattutto ext4. Quando lo spazio è esaurito e nulla di evidente lo occupa, disaccordo tra df e du su un disco pieno tratta il caso del file eliminato ma ancora aperto che lo causa.

Un dettaglio spiega un sintomo poco chiaro in questo caso. ext4 riserva una parte dei propri blocchi per root quando il filesystem viene creato, quindi root continua a scrivere anche dopo che agli utenti normali viene rifiutata la scrittura. sudo sembra quindi risolvere il problema, il disco si riempie completamente e il problema si ripresenta in una forma peggiore.

Poiché nano tronca il file prima di scrivere il nuovo contenuto, una scrittura che esaurisce lo spazio a metà può lasciare il file più corto di prima. Copia una configurazione importante prima di modificarla su un filesystem quasi pieno. sudo cp -a /etc/nginx/nginx.conf /root/nginx.conf.bak mantiene proprietario, gruppo e permessi sulla copia.

Causa 4: stai modificando un bind mount dall'interno di un container

La proprietà dei file è numerica. Il kernel memorizza un ID utente e il nome visualizzato dipende dal file `/etc/passwd usato per la ricerca. Di conseguenza, lo stesso file può mostrare un nome sull'host e un nome diverso, oppure soltanto un numero, nel container. Confronta gli ID numerici, non i nomi: esegui id -u nel container e ls -ln` sul file.

Un file montato tramite bind mount conserva la proprietà che ha sull'host. Se il file sull'host appartiene al tuo utente e il processo nel container viene eseguito con un altro utente, la scrittura nel container viene rifiutata. Inoltre, `sudo` eseguito nel container non modifica il proprietario del file sull'host. Risolvi il problema dall'host impostando come proprietario l'ID con cui viene eseguito il container, oppure esegui il container con l'ID che possiede già i file. Le immagini di linuxserver.io e di progetti simili espongono le variabili PUID e PGID che impostano l'utente con cui viene eseguito il processo.

È utile conoscere altri due casi relativi ai container. Un mount reso di sola lettura con `:ro, oppure un container avviato con --read-only, rifiuta le scritture indipendentemente dalla proprietà. cat /proc/mounts` eseguito nel container mostra il flag. Con rootless Podman, uno user namespace associa gli ID utente del container a un intervallo di ID sull'host. Di conseguenza, un file che nel container sembra appartenere a root appartiene all'esterno al tuo account senza privilegi.

Esiste anche il caso della modifica che riesce e poi scompare. Un file modificato nel container, in un percorso che non è un mount, si trova nel layer scrivibile del container. Quel layer viene eliminato quando il container viene ricreato. Modifica il file sul lato host del mount oppure durante la build dell'immagine, se la modifica deve essere permanente.

La via di uscita: salvare il file in un percorso di cui si dispone

Non cercare di ottenere privilegi dall'interno dell'editor. Premi Ctrl-O, cancella il percorso nel prompt, inserisci un percorso nella tua home directory, ad esempio /home/you/nginx.conf.new, quindi premi Invio. Poi premi Ctrl-X per uscire. Il file è ora salvato su disco, appartiene al tuo account e il resto consiste in una normale copia del file.

sudo cp /home/you/nginx.conf.new /etc/nginx/nginx.conf
sudo nginx -t

Qui usa cp invece di mv. cp scrive nel file già presente, che mantiene quindi proprietario, gruppo e permessi. mv, sullo stesso filesystem, lo sostituisce con il tuo file. Il risultato è un file di configurazione in /etc di proprietà del tuo account utente, creando il problema di permessi successivo che devi risolvere.

Controlla il risultato con lo strumento che gestisce il file prima di ricaricare qualsiasi configurazione. sudo nginx -t analizza la configurazione di nginx, mentre sudo sshd -t analizza la configurazione del server SSH. Due file dispongono di editor dedicati che eseguono l'intera procedura: sudo visudo per /etc/sudoers e crontab -e per i tuoi cron job. Ciascun editor modifica una copia temporanea, verifica la sintassi e installa il file solo se l'analisi ha esito positivo.

FAQ

Devo usare sudo nano o sudoedit per modificare un file di sistema?

Usa sudoedit. Copia il file in una copia temporanea di tua proprietà, avvia l'editor con il tuo utente e riscrive il risultato come root quando l'editor termina. In questo modo l'editor non dispone mai dei privilegi di root. Imposta SUDO_EDITOR, VISUAL o EDITOR su nano per scegliere nano. Anche sudo nano funziona, ma concede a un editor interattivo l'accesso come root a ogni percorso del sistema per tutta la durata della sessione. Basta quindi un nome file digitato male al prompt di salvataggio per danneggiare un file di sistema.

Per salvare un file con nano è necessaria l'autorizzazione di scrittura sulla directory?

Non per un file già esistente. nano scrive direttamente nel file, quindi il kernel controlla il bit di scrittura sul file e il bit di esecuzione su ogni directory del percorso. Il bit di scrittura della directory è importante quando il file non esiste ancora, perché è necessario creare un nuovo nome, e quando sono attivi i backup o il locking dei file, perché entrambi scrivono un secondo file accanto all'originale.

Il proprietario è corretto e il disco non è pieno. Che cos'altro può impedire la scrittura?

Quattro cose. Il filesystem potrebbe essere montato in sola lettura, come mostra findmnt -no OPTIONS -T /etc/nginx/nginx.conf. Il file potrebbe avere l'attributo immutable, che lsattr mostra e sudo chattr -i rimuove; finché l'attributo è impostato, neppure root può scrivere nel file. Su ext4, il pool di inode potrebbe essere esaurito anche se resta spazio libero, come mostra df -i. SELinux o AppArmor potrebbero negare la scrittura anche se i bit dei permessi la consentono. Il log di audit registra normalmente il rifiuto, ma le regole dontaudit di SELinux possono bloccare una scrittura senza registrare nulla. sudo semodule -DB disabilita temporaneamente queste regole mentre riproduci il problema, mentre sudo semodule -B le riabilita.

Dove salvo le modifiche quando il file non viene salvato in alcun modo?

Premi Ctrl-O e specifica un percorso di tua proprietà, nella tua home directory o in qualsiasi altra posizione in cui il tuo utente possa scrivere. Il buffer è ancora in memoria, quindi non perdi nulla di ciò che hai digitato. Copia poi il file salvato nella posizione corretta con sudo cp, che mantiene il proprietario e i permessi del file originale, quindi controllalo con il comando di test del servizio prima di ricaricare il servizio.

Perché le modifiche effettuate all'interno di un container Docker scompaiono?

Quando il percorso non è un mount, la modifica viene scritta nel writable layer di quel container, che viene eliminato quando il container viene sostituito. Modifica il file sul lato host di un bind mount o di un volume, oppure includilo nell'immagine. Quando il percorso è un bind mount e il salvataggio viene invece rifiutato, confronta id -u all'interno del container con il proprietario numerico mostrato da ls -ln: il file mantiene il proprietario dell'host e il processo del container deve corrispondere a quell'identificativo.