Nano : impossible d’enregistrer, permission denied
L’erreur « Permission denied » dans nano vient souvent du propriétaire ou du dossier parent. Vérifiez aussi un système en lecture seule, plein ou un uid de conteneur.
Pourquoi nano ne peut pas enregistrer votre fichier
nano ne peut pas enregistrer votre fichier pour l’une de quatre raisons : vous n’êtes pas propriétaire du fichier, le répertoire parent n’autorise pas l’opération que nano tente d’effectuer, le système de fichiers est monté en lecture seule ou n’a plus d’espace disponible, ou vous êtes dans un conteneur qui s’exécute avec un autre ID utilisateur. Les deux premières causes sont liées aux permissions, contrairement aux deux dernières. Vérifiez-les dans cet ordre, car la première cause couvre la plupart des cas, se confirme avec une seule commande et se corrige avec sudoedit plutôt qu’avec sudo nano.
Rien n’est perdu tant que l’éditeur est ouvert. Votre texte reste en mémoire. Vous pouvez donc laisser le fichier ouvert, enregistrer le buffer dans un chemin dont vous êtes propriétaire, puis remplacer le fichier initial. Cette solution de secours est présentée vers la fin de ce guide.
Effectuez ces vérifications avant de modifier les permissions
Pointez chaque commande vers le chemin réel que vous modifiez. Elles répondent à des questions différentes. Exécutez-les toutes avant de toucher à quoi que ce soit. Modifier les permissions avant d’avoir identifié le contrôle qui échoue crée généralement un deuxième 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. C’est une question distincte, avec une réponse distincte. namei -l parcourt chaque élément 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 associé à ce chemin et les options avec lesquelles il a été monté. df -h indique l’espace libre. df -i indique le nombre d’inodes libres, qui peuvent être épuisés indépendamment de l’espace disque. Si ces chaînes de permissions ne vous sont pas encore familières, commencez par apprendre à lire la chaîne de permissions affichée par ls -l.
Cause 1 : le fichier appartient à root et vous n’êtes pas root
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, en affiche le contenu et vous permet de saisir du texte : aucune de ces opérations n’écrit sur le disque. Le refus intervient lors de l’enregistrement, quand le kernel compare votre identifiant utilisateur et vos identifiants de groupe au propriétaire, au groupe et aux bits réservés aux autres utilisateurs du fichier. nano relaie le message du kernel ; aucune option de nano ne modifiera donc le résultat.
id et ls -l suffisent à le confirmer. Le fichier appartient à root, vous n’êtes pas root et les bits réservés aux autres utilisateurs 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, vous en attribue la propriété, lance nano sur cette copie avec votre compte utilisateur, puis remet le résultat à son emplacement 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 la même commande sous un autre nom. L’éditeur est choisi dans SUDO_EDITOR, puis VISUAL, puis EDITOR. Ainsi, export EDITOR=nano dans votre profil shell définit cet éditeur par défaut partout. Si l’option env_editor est désactivée dans sudoers, ces variables sont ignorées et l’éditeur est défini par le paramètre editor de sudoers.
sudo nano enregistre également le fichier, et c’est là que se trouve le problème. Il donne à un éditeur interactif complet les privilèges root sur l’ensemble du système de fichiers pendant toute la durée de la session. Une simple erreur de chemin lors de l’invite d’enregistrement peut donc écraser un autre fichier système avec les privilèges root. Travailler avec un compte utilisateur ordinaire 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 et refuse de modifier un fichier situé dans un répertoire dans lequel vous pouvez écrire, 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é). Un fichier qui n’existe pas encore 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 par-dessus l’ancien. nano ne fonctionne pas ainsi. Il ouvre le fichier que vous avez 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 tout de même d’autres opérations, ce qui explique pourquoi ls -ld figure dans la liste de vérifications :
- 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 sont activées par l’option
-Bou parset backupdans un nanorc. Le verrouillage est activé par-Gouset locking. Ces deux fonctions sont désactivées, sauf si vous ou votre distribution les avez activées.
Les permissions des répertoires jouent le même rôle ailleurs sur le système. Le serveur SSH refuse une key lorsque votre répertoire personnel ou votre répertoire .ssh est accessible en écriture par d’autres utilisateurs. C’est une cause fréquente du refus de votre key par SSH lors de la connexion.
Comme nano écrit dans le fichier déjà présent, celui-ci conserve son inode, c’est-à-dire l’identité du fichier sur le disque qui se trouve derrière son nom. Tout processus qui maintient le fichier ouvert continue de le suivre, et un fichier unique monté avec 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: the filesystem is read only, or it has nothing left
findmnt reporting ro in the options means the write was never going to succeed. Either the filesystem was mounted that way, through /etc/fstab or a read only bind mount, or the kernel remounted it read only after a disk error. The second case is the serious one. sudo dmesg -T | tail -50 shows the input/output and filesystem errors that led to the remount, and the repair is a filesystem check while it is unmounted, which on a VPS means booting the provider's rescue console.
A full filesystem fails the same write for a different reason. df -h covers the ordinary case. df -i covers the case people miss: inodes come from a fixed pool created when the filesystem was made, and a tree of tiny files can use them all while df -h still shows free gigabytes. When space is gone and nothing obvious is holding it, df and du disagreeing about a full disk covers the deleted-but-still-open file that causes it.
One detail explains a confusing symptom here. ext4 reserves a share of its blocks for root when the filesystem is created, so root keeps writing after ordinary users are refused. sudo then looks like the fix, the disk fills the rest of the way, and the problem returns in a worse form.
Because nano truncates the file before writing the new contents, a write that runs out of space partway can leave the file shorter than it was. Copy a config you care about before editing it on a filesystem that is nearly full. sudo cp -a /etc/nginx/nginx.conf /root/nginx.conf.bak keeps the owner, group and permissions on the copy.
Cause 4 : vous modifiez un bind mount depuis un conteneur
La propriété des fichiers est numérique. Le kernel stocke un identifiant utilisateur, et le nom affiché vient du /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 simplement un nombre. Comparez les identifiants plutôt que les noms : exécutez id -u dans le conteneur et ls -ln sur le fichier.
Un fichier monté avec un bind mount 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 du fichier sur l’hôte. Corrigez le problème depuis l’hôte en attribuant le fichier à l’identifiant utilisé par le conteneur, ou exécutez le conteneur avec l’identifiant 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 montage rendu accessible en lecture seule avec :ro, ou un conteneur démarré avec --read-only, refuse les écritures quelle que soit la propriété du fichier. cat /proc/mounts exécuté dans le conteneur affiche ce flag. Avec Podman rootless, un user namespace associe les identifiants des utilisateurs du conteneur à une plage d’identifiants sur l’hôte. Un fichier qui semble appartenir à root dans le conteneur appartient donc à votre compte non privilégié à l’extérieur.
Il existe aussi le cas où la modification réussit avant de disparaître. Un fichier modifié dans un conteneur, sur un chemin qui n’est pas un montage, se trouve dans la couche inscriptible du conteneur. Cette couche est supprimée lorsque le conteneur est recréé. Modifiez le fichier du côté hôte du montage, 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 proposé, 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 le reste se résume à 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à présent, 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 se retrouve alors appartenir à votre compte utilisateur, ce qui crée un nouveau 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 à votre place : 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 compte utilisateur, puis réécrit le résultat en tant que root à la fermeture de l’éditeur. L’éditeur 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 toute la session. Une simple faute de frappe dans le nom du fichier à l’enregistrement peut alors endommager un fichier système.
Dois-je avoir le droit 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 fichiers 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 causes sont possibles. Le filesystem est peut-être monté en lecture seule, ce que findmnt -no OPTIONS -T /etc/nginx/nginx.conf permet de vérifier. Le fichier possède peut-être l’attribut immutable, ce que lsattr permet d’afficher et sudo chattr -i de supprimer. Même root ne peut pas écrire dans le fichier tant que cet attribut est défini. Le pool d’inodes est peut-être épuisé alors qu’il reste de l’espace libre, ce que df -i permet de vérifier. SELinux ou AppArmor peut refuser l’écriture même si les bits de permission l’autorisent. Le journal d’audit enregistre alors le refus avec le chemin que vous avez tenté d’utiliser.
Où enregistrer mes modifications si le fichier refuse complètement de s’enregistrer ?
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 original. Vérifiez ensuite le fichier avec la commande de test du service avant de recharger le service.
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 côté host d’un bind mount ou d’un volume, ou intégrez-le à 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 obtenu avec ls -ln. Le fichier conserve son ownership côté host, et le processus du conteneur doit utiliser le même identifiant.