Nano : résoudre « Permission denied » à l’enregistrement
Nano affiche « Permission denied » à l’enregistrement ? Vérifiez le propriétaire, le répertoire parent, le système de fichiers et votre uid dans le conteneur.
Pourquoi nano n’enregistre pas votre fichier
nano n’enregistre pas votre fichier pour l’une de ces quatre raisons : vous n’en êtes pas propriétaire, le répertoire parent n’autorise pas l’opération que nano tente d’effectuer, le système de fichiers est en lecture seule ou manque d’espace, ou vous êtes dans un conteneur exécuté avec un autre identifiant utilisateur. Les deux premières sont des problèmes de permissions, contrairement aux deux dernières. Vérifiez ces causes dans cet ordre, car la première couvre la plupart des cas, se confirme avec une seule commande et se corrige avec sudoedit plutôt qu’avec sudo nano.
Tant que l’éditeur est ouvert, rien n’est perdu. Votre texte reste en mémoire. Vous pouvez donc laisser le fichier ouvert, écrire le buffer dans un chemin dont vous êtes propriétaire, puis le remettre à son emplacement initial. Cette solution de secours est présentée vers la fin de ce guide.
Effectuez ces vérifications avant de modifier les permissions
Indiquez le chemin réel que vous modifiez dans chaque commande. Ces commandes répondent à des questions différentes. Exécutez-les toutes avant de modifier quoi que ce soit. Modifier les permissions avant de savoir quelle vérification échoue crée généralement un second problème en plus du premier.
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/nginxid affiche l’ID utilisateur et les ID de groupe dont vous disposez actuellement. ls -l affiche le propriétaire, le groupe et les bits de permission du fichier lui-même. ls -ld affiche les mêmes informations pour le répertoire qui le contient, ce qui constitue une question distincte avec une réponse distincte. namei -l parcourt chaque composant du chemin et affiche le propriétaire et les permissions de chacun. Il répond donc aux deux questions dans une seule sortie. findmnt indique le système de fichiers utilisé pour ce chemin et les options avec lesquelles il a été monté. df -h indique l’espace libre, tandis que df -i indique le nombre d’inodes libres, qui peuvent être épuisés indépendamment de l’espace. Si la lecture de ces chaînes de permissions ne vous est pas encore familière, commencez par lire la chaîne de permissions affichée par ls -l.
Cause 1 : le fichier appartient à root et vous ne l’êtes pas
Les permissions de lecture et d’écriture sont distinctes, et la plupart des fichiers sous /etc sont lisibles par tout le monde. C’est pourquoi nano ouvre le fichier, affiche son contenu et vous permet de saisir du texte librement : rien de tout cela ne modifie le disque. Le refus survient lors de l’enregistrement, lorsque le kernel compare votre ID utilisateur et vos ID de groupe au propriétaire, au groupe et aux bits « other » du fichier. nano relaie le refus renvoyé par le kernel ; aucune option de nano ne peut donc modifier le résultat.
id et ls -l permettent de le confirmer. Le fichier appartient à root, vous n’êtes pas root et les bits « other » n’accordent pas la permission d’écriture. Appuyer de nouveau sur Ctrl-O ne changera rien.
Pourquoi sudoedit est la bonne méthode pour modifier un fichier appartenant à root
SUDO_EDITOR=nano sudoedit /etc/nginx/nginx.confsudo crée une copie temporaire du fichier dont vous êtes propriétaire, lance nano sur cette copie avec votre compte utilisateur, puis remet le résultat en place avec les privilèges root lorsque l’éditeur se ferme. L’éditeur ne s’exécute jamais avec les privilèges root. sudo -e est le même commande sous un autre nom. L’éditeur est choisi dans SUDO_EDITOR, puis VISUAL, puis EDITOR. Définir export EDITOR=nano dans votre profil shell en fait donc l’éditeur par défaut partout. Si la directive env_editor est désactivée dans sudoers, ces variables sont ignorées et l’éditeur est déterminé par le paramètre editor de sudoers.
sudo nano enregistre également le fichier, et c’est là le problème. Il donne à l’éditeur interactif complet les privilèges root sur tout le système de fichiers pendant toute la durée de la session. Une simple erreur de chemin à l’invite d’enregistrement peut donc remplacer un autre fichier système par votre texte, avec les privilèges root. Travailler avec un compte utilisateur normal et n’appeler sudo que pour les étapes qui l’exigent est une bonne habitude à prendre. sudoedit applique cette habitude lorsque vous modifiez un fichier de configuration.
Deux règles de sudoedit surprennent souvent. sudoedit refuse de modifier un lien symbolique. Il refuse également de modifier un fichier situé dans un répertoire sur lequel vous avez les droits d’écriture, sauf si vous êtes root. Cette deuxième règle existe parce que toute personne pouvant écrire dans le répertoire peut remplacer le fichier pendant que l’éditeur est ouvert. Ces deux comportements correspondent aux valeurs par défaut de sudoers (sudoedit_follow désactivé, sudoedit_checkdir activé). Si le fichier n’existe pas encore, il est créé pour vous.
Cause 2 : ce que le répertoire parent contrôle réellement
Les conseils destinés à d’autres éditeurs indiquent qu’un enregistrement nécessite le droit d’écriture sur le répertoire, car de nombreux éditeurs enregistrent en écrivant un nouveau fichier, puis en le renommant pour remplacer l’ancien. nano ne fonctionne pas ainsi. Il ouvre le fichier indiqué et écrit dans ce fichier. Pour un fichier qui existe déjà, le bit d’écriture du répertoire n’est donc jamais consulté.
Le répertoire contrôle néanmoins d’autres opérations. C’est pourquoi ls -ld figure dans la liste de vérification :
- La création d’un fichier qui n’existe pas encore nécessite les droits d’écriture et d’exécution sur le répertoire, car il faut y ajouter un nouveau nom. Votre umask détermine les permissions initiales de ce nouveau fichier.
- L’accès au fichier nécessite le droit d’exécution, également appelé droit de recherche, sur chaque répertoire du chemin. Un seul répertoire qui ne possède pas ce droit bloque tout ce qui se trouve en dessous.
namei -lindique lequel. - L’enregistrement avec des sauvegardes ou avec le verrouillage de fichiers activé écrit un second fichier à côté de l’original. Ces fonctions nécessitent donc un répertoire accessible en écriture. Les sauvegardes correspondent à l’option
-Bou àset backupdans un nanorc, et le verrouillage à-Gouset locking. Ces deux fonctions sont désactivées sauf si vous ou votre distribution les avez activées.
Les permissions des répertoires ont la même importance ailleurs sur le système. Le serveur SSH refuse une clé lorsque votre répertoire personnel ou votre répertoire .ssh peut être modifié par d’autres utilisateurs. C’est une cause fréquente de refus de votre clé SSH à la connexion.
Comme nano écrit dans le fichier qui existe déjà, celui-ci conserve son inode, c’est-à-dire l’identité du fichier sur le disque derrière son nom. Tout processus qui garde le fichier ouvert continue de le suivre, et un fichier unique monté par bind dans un conteneur continue de fonctionner. Les éditeurs qui enregistrent en remplaçant le fichier interrompent ce montage, car celui-ci suit l’inode et non le nom.
Cause 3 : le système de fichiers est en lecture seule ou n’a plus d’espace libre
Le message findmnt reporting ro dans les options indique que l’écriture ne pouvait pas réussir. Soit le système de fichiers a été monté ainsi, via /etc/fstab ou avec un bind mount en lecture seule, soit le kernel l’a remonté en lecture seule après une erreur disque. Le deuxième cas est le plus grave. sudo dmesg -T | tail -50 affiche les erreurs d’entrée/sortie et de système de fichiers qui ont entraîné le remontage. Pour corriger le problème, vérifiez le système de fichiers alors qu’il est démonté. Sur un VPS, cela signifie démarrer la console de secours du fournisseur.
Un système de fichiers plein échoue sur la même opération d’écriture, mais pour une autre raison. df -h couvre le cas courant. df -i couvre le cas souvent oublié : les inodes proviennent d’un pool fixe créé lors de la création du système de fichiers, et une arborescence remplie de petits fichiers peut tous les consommer alors que df -h indique encore plusieurs gigaoctets libres. Lorsque l’espace est épuisé et que rien ne semble le retenir, df et du indiquent des résultats différents pour un disque plein traite le cas du fichier supprimé mais toujours ouvert qui en est la cause.
Un détail explique ce comportement déroutant. Lors de la création du système de fichiers, ext4 réserve une partie de ses blocs à root. root peut donc continuer à écrire alors que les utilisateurs ordinaires sont refusés. sudo semble alors résoudre le problème, le disque se remplit jusqu’au bout, puis le problème réapparaît sous une forme plus grave.
Comme nano tronque le fichier avant d’écrire le nouveau contenu, un enregistrement qui manque d’espace en cours d’opération peut laisser le fichier plus court qu’auparavant. Copiez les fichiers de configuration importants avant de les modifier sur un système de fichiers presque plein. sudo cp -a /etc/nginx/nginx.conf /root/nginx.conf.bak conserve le propriétaire, le groupe et les permissions de la copie.
Cause 4 : vous modifiez un bind mount depuis un conteneur
La propriété des fichiers est stockée sous forme numérique. Le kernel stocke un ID utilisateur, et le nom affiché dépend de l’outil /etc/passwd qui effectue la résolution. Un même fichier peut donc afficher un nom sur l’hôte, un autre nom dans le conteneur, ou uniquement un nombre. Comparez les nombres plutôt que les noms : exécutez id -u dans le conteneur et ls -ln sur le fichier.
Un fichier monté par bind conserve la propriété qu’il a sur l’hôte. Si le fichier de l’hôte appartient à votre utilisateur et que le processus du conteneur s’exécute avec un autre utilisateur, l’écriture est refusée dans le conteneur. De plus, sudo exécuté dans le conteneur ne modifie pas le propriétaire sur l’hôte. Corrigez le problème depuis l’hôte en attribuant le fichier à l’ID avec lequel le conteneur s’exécute, ou exécutez le conteneur avec l’ID qui possède déjà les fichiers. Les images de linuxserver.io et de projets similaires exposent les variables PUID et PGID qui définissent l’utilisateur avec lequel le processus s’exécute.
Deux autres cas liés aux conteneurs sont à connaître. Un mount créé en lecture seule avec :ro, ou un conteneur démarré avec --read-only, refuse les écritures quelle que soit la propriété du fichier. La commande cat /proc/mounts exécutée dans le conteneur affiche ce flag. Avec Podman rootless, un user namespace associe les IDs utilisateurs du conteneur à une plage d’IDs sur l’hôte. Un fichier qui semble appartenir à root dans le conteneur appartient donc à votre compte non privilégié en dehors du conteneur.
Il existe aussi le cas où la modification réussit, puis disparaît. Un fichier modifié dans un conteneur, sur un chemin qui n’est pas un mount, se trouve dans la writable layer de ce conteneur. Cette couche est supprimée lorsque le conteneur est recréé. Modifiez le fichier du côté hôte du mount, ou dans le build de l’image, si la modification doit être conservée.
La solution de repli : l’enregistrer dans un chemin dont vous êtes propriétaire
N’essayez pas d’obtenir des privilèges depuis l’éditeur. Appuyez sur Ctrl-O, effacez le chemin affiché à l’invite, saisissez un chemin sous votre répertoire personnel, par exemple /home/you/nginx.conf.new, puis appuyez sur Entrée. Appuyez ensuite sur Ctrl-X pour quitter. Votre travail est maintenant enregistré sur le disque, vous en êtes propriétaire, et la suite consiste en une copie de fichier ordinaire.
sudo cp /home/you/nginx.conf.new /etc/nginx/nginx.conf
sudo nginx -tUtilisez cp ici plutôt que mv. cp écrit dans le fichier déjà en place, qui conserve donc son propriétaire, son groupe et ses permissions. Sur le même système de fichiers, mv le remplace par votre fichier. La configuration située dans /etc appartient alors à votre compte utilisateur, ce qui crée le prochain problème de permissions à résoudre.
Vérifiez le résultat avec l’outil qui gère le fichier avant de recharger quoi que ce soit. sudo nginx -t analyse la configuration nginx, et sudo sshd -t analyse la configuration du serveur SSH. Deux fichiers disposent d’éditeurs dédiés qui effectuent toute cette procédure pour vous : sudo visudo pour /etc/sudoers et crontab -e pour vos propres tâches cron. Chacun modifie une copie temporaire, vérifie la syntaxe et installe le fichier uniquement si l’analyse réussit.
FAQ
Dois-je utiliser sudo nano ou sudoedit pour modifier un fichier système ?
Utilisez sudoedit. Cette commande copie le fichier dans une copie temporaire qui vous appartient, lance votre éditeur avec votre utilisateur, puis réécrit le résultat en tant que root à la fermeture de l’éditeur. L’éditeur lui-même ne dispose donc jamais des privilèges root. Définissez SUDO_EDITOR, VISUAL ou EDITOR sur nano pour sélectionner nano. sudo nano fonctionne aussi, mais donne à un éditeur interactif un accès root à tous les chemins du système pendant la session. Une simple faute de frappe dans le nom du fichier à l’enregistrement peut alors endommager un fichier système.
Dois-je avoir la permission d’écriture sur le répertoire pour enregistrer un fichier avec nano ?
Pas pour un fichier qui existe déjà. nano écrit directement dans le fichier. Le kernel vérifie donc le bit d’écriture du fichier et le bit d’exécution de chaque répertoire du chemin. Le bit d’écriture du répertoire est nécessaire lorsque le fichier n’existe pas encore, car il faut créer un nouveau nom. Il est également nécessaire lorsque les sauvegardes ou le verrouillage de fichier sont activés, car ces fonctions écrivent un second fichier à côté de l’original.
Le propriétaire semble correct et le disque n’est pas plein. Qu’est-ce qui peut encore bloquer l’écriture ?
Quatre éléments peuvent être en cause. Le filesystem peut être monté en lecture seule, ce que findmnt -no OPTIONS -T /etc/nginx/nginx.conf indique. Le fichier peut avoir l’attribut immutable, que lsattr affiche et que sudo chattr -i supprime. Même root ne peut pas écrire dans le fichier tant que cet attribut est défini. Le pool d’inodes peut être épuisé alors qu’il reste de l’espace libre, ce que df -i indique. SELinux ou AppArmor peut refuser l’écriture même si les bits de permission l’autorisent. Le journal d’audit enregistre alors le refus pour le chemin que vous avez tenté d’utiliser.
Où placer mes modifications si le fichier ne peut pas être enregistré du tout ?
Appuyez sur Ctrl-O et indiquez un chemin qui vous appartient, sous votre répertoire personnel ou à tout autre emplacement où votre utilisateur peut écrire. Le buffer est toujours en mémoire. Rien de ce que vous avez saisi n’est donc perdu. Copiez ensuite le fichier enregistré à son emplacement avec sudo cp. Cette commande conserve le propriétaire et les permissions du fichier d’origine. Vérifiez ensuite le fichier avec la commande de test propre au service avant de recharger celui-ci.
Pourquoi mes modifications dans un conteneur Docker disparaissent-elles ?
Lorsque le chemin n’est pas un mount, la modification est écrite dans la writable layer du conteneur. Cette couche est supprimée lorsque le conteneur est remplacé. Modifiez le fichier du côté host d’un bind mount ou d’un volume, ou intégrez-le dans l’image. Lorsque le chemin est un bind mount et que l’enregistrement est refusé, comparez id -u dans le conteneur avec le propriétaire numérique indiqué par ls -ln. Le fichier conserve son propriétaire côté host, et le processus du conteneur doit utiliser le même.