SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor

Nano no guarda: error de permisos y cómo resolverlo

Si nano muestra Permission denied al guardar, comprueba propietario, directorio padre, sistema de archivos de solo lectura o lleno y tu uid en el contenedor.

Por qué nano no guarda el archivo

nano no guarda el archivo por uno de estos cuatro motivos: no es propietario del archivo, el directorio padre no permite la operación que nano intenta realizar, el sistema de archivos es de solo lectura o no tiene espacio, o está dentro de un contenedor que se ejecuta con otro ID de usuario. Los dos primeros son problemas de permisos y los dos últimos no lo son. Compruébelos en ese orden porque el primer motivo cubre la mayoría de los casos, se confirma con un solo comando y su solución es sudoedit en lugar de sudo nano.

No se pierde nada mientras el editor siga abierto. El texto permanece en memoria, por lo que puede dejar el archivo abierto, escribir el búfer en una ruta de la que sea propietario y colocarlo después en su ubicación. Esta alternativa se explica cerca del final de esta guía.

Ejecute estas comprobaciones antes de cambiar permisos

Apunte cada comando a la ruta real que está editando. Cada uno responde a una pregunta diferente, por lo que debe ejecutarlos todos antes de modificar nada. Cambiar los permisos sin saber qué comprobación falla suele crear un segundo problema además del primero.

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 muestra el ID de usuario y los ID de grupo que tiene en este momento. ls -l muestra el propietario, el grupo y los bits de permisos del propio archivo. ls -ld muestra lo mismo para el directorio que lo contiene, que es una pregunta independiente con una respuesta independiente. namei -l recorre cada parte de la ruta y muestra el propietario y los permisos de cada una, por lo que responde a ambas preguntas en una sola salida. findmnt indica el sistema de archivos situado bajo esa ruta y las opciones con las que se montó. df -h informa del espacio libre y df -i informa de los inodos libres, que se agotan por separado del espacio. Si esas cadenas de permisos aún no le resultan familiares, empiece por cómo leer la cadena de permisos que muestra ls -l.

Causa 1: el archivo pertenece a root y usted no

Los permisos de lectura y escritura son independientes, y la mayoría de los archivos de /etc pueden ser leídos por cualquier usuario. Por eso nano abre el archivo, muestra su contenido y permite escribir en él: ninguna de esas acciones modifica el disco. El rechazo se produce al guardar, cuando el kernel compara su ID de usuario y sus ID de grupo con el propietario, el grupo y los permisos para otros usuarios del archivo. nano sólo muestra la respuesta del kernel, por lo que ninguna opción de nano cambia el resultado.

id y ls -l lo confirman. El archivo pertenece a root, usted no es root y los permisos para otros usuarios no conceden escritura. Pulsar Ctrl-O de nuevo no solucionará el problema.

Por qué sudoedit es la forma correcta de editar un archivo propiedad de root

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

sudo crea una copia temporal del archivo cuyo propietario eres tú, ejecuta nano sobre esa copia con tu usuario y, cuando el editor termina, copia el resultado a su ubicación con privilegios de root. El editor nunca se ejecuta como root. sudo -e es el mismo comando con otro nombre. El editor se elige primero desde SUDO_EDITOR, después desde VISUAL y, por último, desde EDITOR, por lo que export EDITOR=nano en tu perfil de shell establece este comportamiento como predeterminado en todas partes. Si ninguna de esas variables especifica un editor existente y ejecutable, sudoedit usa el valor de editor en sudoers, que de forma predeterminada es vi.

sudo nano también guarda el archivo, y ese es el problema. Concede al editor interactivo completo privilegios de root sobre todo el sistema de archivos mientras dura la sesión. Por tanto, una ruta escrita por error en el indicador de guardado puede sobrescribir otro archivo del sistema con permisos de root. Trabajar como un usuario normal que usa sudo sólo para los pasos que lo necesitan es el hábito que conviene adquirir, y sudoedit es la forma de aplicar ese hábito al editar un archivo de configuración.

Dos reglas de sudoedit sorprenden a muchos usuarios. Se niega a editar un enlace simbólico y también se niega a editar un archivo situado dentro de un directorio en el que puedes escribir, a menos que seas root. La segunda regla existe porque cualquiera que pueda escribir en el directorio puede sustituir el archivo mientras el editor está abierto. Ambos comportamientos son los valores predeterminados de sudoers (sudoedit_follow desactivado, sudoedit_checkdir activado). Si el archivo todavía no existe, sudoedit lo crea.

Causa 2: qué controla realmente el directorio padre

Las recomendaciones escritas para otros editores indican que guardar un archivo requiere permiso de escritura en el directorio, porque muchos editores guardan escribiendo un archivo nuevo y cambiándole el nombre para reemplazar el anterior. nano no funciona así. Abre el archivo indicado y escribe en ese mismo archivo. Por tanto, si el archivo ya existe, nunca se consulta el bit de escritura del directorio.

El directorio sigue controlando otros aspectos. Por eso ls -ld aparece en la lista de comprobaciones:

  • Crear un archivo que todavía no existe requiere permisos de escritura y ejecución en el directorio, porque es necesario añadirle un nombre nuevo. umask determina los permisos iniciales de ese archivo nuevo.
  • Para llegar al archivo se necesita permiso de ejecución, también llamado permiso de búsqueda, en todos los directorios de la ruta. Si falta en uno de ellos, se bloquea todo lo que hay debajo, y namei -l muestra cuál es.
  • Guardar con copias de seguridad o con el bloqueo de archivos activado escribe un segundo archivo junto al original. Por tanto, estas funciones sí requieren un directorio con permiso de escritura. Las copias de seguridad se controlan con la opción -B o con set backup en un nanorc, y el bloqueo con -G o set locking. Ambas funciones están desactivadas, salvo que usted o su distribución las hayan activado.

Los permisos de los directorios tienen la misma importancia en otras partes del sistema. El servidor SSH rechaza una clave si otros usuarios pueden escribir en su directorio personal o en su directorio .ssh. Esta es una causa habitual de que SSH rechace su clave durante el inicio de sesión.

Como nano escribe en el archivo que ya existe, el archivo conserva su inode, que es la identidad del archivo en el disco asociada a su nombre. Cualquier proceso que mantenga abierto el archivo sigue trabajando con él, y un archivo individual montado mediante bind en un contenedor continúa funcionando. Los editores que guardan reemplazando el archivo rompen ese montaje, porque el montaje sigue el inode y no el nombre.

Causa 3: el sistema de archivos es de solo lectura o no le queda espacio

findmnt indica ro en las opciones significa que la escritura nunca iba a completarse correctamente. El sistema de archivos se montó así, mediante /etc/fstab o mediante un bind mount de solo lectura, o el kernel lo volvió a montar como de solo lectura después de un error de disco. El segundo caso es el grave. sudo dmesg -T | tail -50 muestra los mensajes más recientes del kernel, pero los errores de entrada/salida y del sistema de archivos que provocaron el remontaje no tienen por qué estar entre las últimas 50 líneas. Ejecute sudo dmesg -T sin tail para ver todos los mensajes que aún conserva el búfer circular del kernel y busque los errores registrados antes del remontaje. La reparación consiste en comprobar el sistema de archivos mientras está desmontado. Un sistema de archivos distinto de root se puede desmontar y comprobar en el mismo sistema. Para root, un arranque normal puede hacerlo: systemd comprueba todos los sistemas de archivos cuyo número de pasada de fsck en /etc/fstab sea mayor que cero, comprueba root en el initrd cuando el initrd lo admite, y fsck.mode=force en la línea de comandos del kernel fuerza una comprobación completa. Si la VPS no arranca lo suficiente para eso, la consola de rescate del proveedor es la alternativa.

Un sistema de archivos lleno provoca el mismo fallo de escritura por un motivo diferente. df -h cubre el caso habitual. df -i cubre el caso que suele pasarse por alto: en ext4, el valor predeterminado habitual, los inodos proceden de un conjunto fijo creado al crear el sistema de archivos, y un árbol de archivos pequeños puede usarlos todos mientras df -h todavía muestra gigabytes libres. XFS asigna inodos a medida que se crean los archivos, por lo que este caso afecta sobre todo a ext4. Cuando no queda espacio y nada evidente lo está ocupando, cuando df y du no coinciden sobre un disco lleno explica el caso de un archivo eliminado que sigue abierto y provoca el problema.

Un detalle explica un síntoma confuso en este caso. ext4 reserva una parte de sus bloques para root al crear el sistema de archivos, por lo que root puede seguir escribiendo después de que se rechacen las escrituras de los usuarios normales. sudo parece entonces solucionar el problema, el disco se llena por completo y el problema vuelve en una forma más grave.

Como nano trunca el archivo antes de escribir el contenido nuevo, una escritura que se queda sin espacio a mitad del proceso puede dejar el archivo más corto de lo que era. Copie la configuración que le importe antes de editarla en un sistema de archivos casi lleno. sudo cp -a /etc/nginx/nginx.conf /root/nginx.conf.bak conserva el propietario, el grupo y los permisos de la copia.

Causa 4: está en un contenedor y edita un bind mount

La propiedad de los archivos se almacena como valores numéricos. El kernel guarda un ID de usuario, y el nombre que se muestra procede de la búsqueda que realiza /etc/passwd. Por eso, un mismo archivo puede mostrar un nombre en el host y otro nombre, o sólo un número, dentro del contenedor. Compare los números, no los nombres: ejecute id -u dentro del contenedor y ls -ln sobre el archivo.

Un archivo montado mediante bind mount conserva la propiedad que tiene en el host. Cuando el archivo del host pertenece a su usuario y el proceso del contenedor se ejecuta con otro usuario, la escritura se rechaza dentro del contenedor. Además, sudo dentro del contenedor no cambia la propiedad del archivo en el host. Corríjalo desde el host asignando el propietario al ID con el que se ejecuta el contenedor, o ejecute el contenedor con el ID que ya es propietario de los archivos. Las imágenes de linuxserver.io y de proyectos similares exponen las variables PUID y PGID que establecen con qué usuario se ejecuta el proceso.

Conviene conocer otros dos casos relacionados con contenedores. Un montaje creado como de sólo lectura con :ro, o un contenedor iniciado con --read-only, rechaza las escrituras independientemente de la propiedad. cat /proc/mounts dentro del contenedor muestra este indicador. Con rootless Podman, un espacio de nombres de usuario asigna los ID de usuario del contenedor a un rango de ID del host. Por eso, un archivo que parece pertenecer a root dentro del contenedor pertenece a su cuenta sin privilegios fuera de él.

También existe el caso de una edición que se aplica y después desaparece. Un archivo que modifica dentro de un contenedor, en una ruta que no es un montaje, reside en la capa escribible del contenedor. Esa capa se descarta cuando se vuelve a crear el contenedor. Modifique el archivo en el lado del host del montaje, o durante la construcción de la imagen, si el cambio debe conservarse.

La salida de emergencia: guárdelo en una ruta de su propiedad

No intente obtener privilegios desde el editor. Pulse Ctrl-O, borre la ruta del indicador, escriba una ruta dentro de su directorio personal, como /home/you/nginx.conf.new, y pulse Enter. Después, pulse Ctrl-X para salir. El archivo ya está guardado en el disco, es de su propiedad y el resto es una copia de archivo normal.

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

Use cp aquí en lugar de mv. cp escribe a través del archivo que ya existe, por lo que ese archivo conserva su propietario, grupo y permisos. mv, en el mismo sistema de archivos, lo reemplaza por su archivo. Esto deja un archivo de configuración en /etc cuyo propietario es su cuenta de usuario, y ese se convierte en el siguiente problema de permisos que debe resolver.

Compruebe el resultado con la herramienta responsable del archivo antes de volver a cargar nada. sudo nginx -t analiza la configuración de nginx y sudo sshd -t analiza la configuración del servidor SSH. Dos archivos tienen editores específicos que realizan todo este procedimiento: sudo visudo para /etc/sudoers y crontab -e para sus propias tareas de cron. Cada uno edita una copia temporal, comprueba la sintaxis e instala el archivo sólo si el análisis es correcto.

FAQ

¿Debo usar sudo nano o sudoedit para editar un archivo del sistema?

Use sudoedit. Copia el archivo en una copia temporal de su propiedad, ejecuta el editor con su usuario y escribe el resultado como root cuando el editor se cierra. De este modo, el editor nunca tiene privilegios de root. Establezca SUDO_EDITOR, VISUAL o EDITOR en nano para seleccionar nano. sudo nano también funciona, pero concede a un editor interactivo acceso de root a todas las rutas del sistema durante la sesión. Un nombre de archivo mal escrito en el indicador de guardado puede convertir esto en un archivo del sistema dañado.

¿Necesito permiso de escritura en el directorio para guardar un archivo con nano?

No si el archivo ya existe. nano escribe directamente en el archivo. Por tanto, el kernel comprueba el bit de escritura del archivo y el bit de ejecución de cada directorio de la ruta. El bit de escritura del directorio importa cuando el archivo todavía no existe, porque hay que crear un nombre nuevo. También importa cuando las copias de seguridad o el bloqueo de archivos están habilitados, porque ambos crean un segundo archivo junto al original.

El propietario es correcto y el disco no está lleno. ¿Qué más puede impedir la escritura?

Hay cuatro posibilidades. El sistema de archivos puede estar montado como de solo lectura, como muestra findmnt -no OPTIONS -T /etc/nginx/nginx.conf. El archivo puede tener el atributo immutable, que muestra lsattr y elimina sudo chattr -i. Ni siquiera root puede escribir en el archivo mientras este atributo esté establecido. En ext4, el grupo de inodos puede haberse agotado aunque quede espacio libre, como muestra df -i. SELinux o AppArmor pueden denegar la escritura aunque los bits de permisos la permitan. El registro de auditoría suele registrar la denegación, pero las reglas dontaudit de SELinux pueden bloquear una escritura sin registrar nada. sudo semodule -DB desactiva esas reglas mientras reproduce el problema y sudo semodule -B vuelve a activarlas.

¿Dónde guardo los cambios si el archivo no se puede guardar de ninguna manera?

Pulse Ctrl-O e indique una ruta de su propiedad, dentro de su directorio personal o en cualquier otra ubicación donde su usuario tenga permiso de escritura. El búfer sigue en memoria, por lo que no se pierde nada de lo que haya escrito. Después, copie el archivo guardado a su ubicación con sudo cp. Este comando conserva el propietario y los permisos del archivo original. A continuación, compruébelo con el comando de prueba propio del servicio antes de volver a cargarlo.

¿Por qué desaparecen mis cambios dentro de un contenedor Docker?

Cuando la ruta no es un montaje, el cambio se escribe en la capa escribible del contenedor. Esa capa se descarta cuando se reemplaza el contenedor. Edite el archivo en el lado del host de un bind mount o de un volumen, o inclúyalo al crear la imagen. Si la ruta es un bind mount y el guardado se rechaza, compare id -u dentro del contenedor con el propietario numérico que muestra ls -ln. El archivo conserva la propiedad del host y el proceso del contenedor debe coincidir con ella.