--- title: "Cómo resolver errores de permisos en Linux (Ubuntu 24.04)" description: "Corrige errores de Permission denied en Ubuntu 24.04: lee permisos con namei y stat, ajusta chmod y chown en webs, SSH y carpetas compartidas, y usa ACL." category: "Guía de Solución de Problemas" language: es source: https://cubepath.com/es/docs/guía-de-solución-de-problemas/problemas-de-permisos-de-archivos updated: 2026-09-25 --- # Cómo resolver errores de permisos en Linux (Ubuntu 24.04) Un `Permission denied` en Linux casi nunca se arregla con `chmod 777`: esa solución abre el archivo a cualquier usuario del sistema y suele ocultar la causa real, que muchas veces es un directorio intermedio de la ruta o el usuario con el que se ejecuta el servicio. En este tutorial aprenderás a leer los permisos de toda una ruta, a comprobar qué puede hacer un usuario concreto y a corregir los casos más frecuentes en Ubuntu 24.04: sitios web con Nginx, claves SSH, carpetas compartidas entre usuarios, servicios y ACL. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Los comandos son idénticos en Debian 12; en Rocky Linux 9 cambia el usuario del servidor web (`nginx` o `apache` en lugar de `www-data`) y SELinux añade su propia capa de control. - Un usuario no root con privilegios `sudo`. En esta guía se llama `your_user`. ## Cómo funcionan los permisos Cada archivo tiene un propietario, un grupo y tres juegos de permisos: para el propietario, para el grupo y para el resto de usuarios. Cada juego combina lectura (`r`), escritura (`w`) y ejecución (`x`): ```output -rw-r----- 1 your_user www-data 2048 Sep 25 10:00 config.php ``` Aquí `your_user` puede leer y escribir, los miembros de `www-data` solo leer y el resto no tiene acceso. En notación numérica, `r` vale 4, `w` 2 y `x` 1, y se suman por juego: `rw-r-----` es `640`. El significado cambia en los directorios, y es la fuente de la mayoría de confusiones: | Permiso | En un archivo | En un directorio | |---|---|---| | `r` | Leer el contenido. | Listar los nombres que contiene. | | `w` | Modificar el contenido. | Crear, borrar o renombrar archivos dentro. | | `x` | Ejecutarlo como programa. | Entrar en él y acceder a lo que contiene. | Para abrir `/var/www/sitio/index.html`, un usuario necesita `x` en **todos** los directorios de la ruta (`/`, `/var`, `/var/www`, `/var/www/sitio`) y `r` en el archivo. Por eso un archivo con permisos correctos puede seguir dando `Permission denied`. Existen además tres permisos especiales: | Permiso | Valor | Efecto habitual | |---|---|---| | setuid | `4000` | Un ejecutable se ejecuta con los privilegios de su propietario (por ejemplo, `passwd`). | | setgid | `2000` | En un directorio, los archivos nuevos heredan el grupo del directorio. | | sticky | `1000` | En un directorio, solo el propietario de un archivo puede borrarlo (por ejemplo, `/tmp`). | ## Paso 1: Leer los permisos de un archivo y de su ruta `ls -l` muestra los permisos de un archivo, y `stat` los muestra también en formato numérico: ```bash stat -c '%A %a %U:%G %n' /var/www/your_domain/index.html ``` ```output -rw-r--r-- 644 your_user:your_user /var/www/your_domain/index.html ``` La herramienta más útil para diagnosticar es `namei -l`, que muestra los permisos de cada componente de la ruta, de la raíz al archivo: ```bash namei -l /home/your_user/sitio/index.html ``` ```output f: /home/your_user/sitio/index.html drwxr-xr-x root root / drwxr-xr-x root root home drwxr-x--- your_user your_user your_user drwxr-xr-x your_user your_user sitio -rw-r--r-- your_user your_user index.html ``` El archivo es legible por todos, pero `/home/your_user` tiene permisos `750`: quien no sea `your_user` ni pertenezca a su grupo no puede atravesarlo. Desde Ubuntu 21.04, los directorios personales se crean con estos permisos, y es la causa de muchos errores `403` cuando un servidor web sirve archivos desde `/home`. Comprueba también con qué usuario y grupos trabajas: ```bash id your_user ``` ```output uid=1000(your_user) gid=1000(your_user) groups=1000(your_user),27(sudo),33(www-data) ``` > Nota: si acabas de añadir un usuario a un grupo con `usermod -aG`, el cambio solo se aplica en las sesiones nuevas. Cierra sesión y vuelve a entrar, o reinicia el servicio afectado. ## Paso 2: Comprobar el acceso como otro usuario La forma más fiable de confirmar un problema de permisos es repetir la operación con el mismo usuario que falla. Con `sudo -u` y el comando `test` puedes comprobar lectura (`-r`), escritura (`-w`) y ejecución (`-x`): ```bash sudo -u www-data test -r /home/your_user/sitio/index.html && echo "puede leer" || echo "NO puede leer" ``` ```output NO puede leer ``` Para comprobar si puede crear archivos en un directorio, intenta crear uno de prueba y bórralo: ```bash sudo -u www-data touch /var/www/your_domain/uploads/prueba && sudo -u www-data rm /var/www/your_domain/uploads/prueba && echo "puede escribir" ``` Si el comando falla con `Permission denied`, usa `namei -l` sobre esa ruta para ver en qué directorio se corta el acceso. ## Paso 3: Corregir scripts que no se ejecutan Al ejecutar un script sin permiso de ejecución obtienes: ```output -bash: ./backup.sh: Permission denied ``` Añade el permiso de ejecución solo para el propietario, o para todos si otros usuarios deben poder ejecutarlo: ```bash chmod u+x backup.sh ``` ```bash ls -l backup.sh ``` ```output -rwxr--r-- 1 your_user your_user 812 Sep 25 10:15 backup.sh ``` Si el script tiene permiso `x` y sigue fallando, comprueba si el sistema de archivos está montado con la opción `noexec`, que impide ejecutar cualquier programa en él: ```bash findmnt -no OPTIONS --target "$PWD" ``` Si aparece `noexec`, mueve el script a otra ubicación, como `/usr/local/bin`, o ejecútalo a través del intérprete: `bash backup.sh`. ## Paso 4: Corregir los permisos de un sitio web En Ubuntu, Nginx y PHP-FPM se ejecutan como `www-data`. Un esquema seguro para `/var/www/your_domain` es: - Los archivos pertenecen a tu usuario (que los despliega) y al grupo `www-data` (que los lee). - Directorios `755` y archivos `644`: el servidor web lee, pero no puede modificar el código. - Solo los directorios donde la aplicación debe escribir (subidas, caché) son propiedad de `www-data`. Primero, identifica el error. Nginx registra los problemas de permisos con el código `13`: ```bash sudo tail -n 20 /var/log/nginx/error.log ``` ```output 2026/09/25 10:20:14 [crit] 1203#1203: *41 stat() "/home/your_user/sitio/index.html" failed (13: Permission denied), client: 198.51.100.24, server: your_domain, request: "GET / HTTP/2.0" ``` La mejor solución para un sitio en `/home` es moverlo a `/var/www`, en lugar de abrir el directorio personal: ```bash sudo mkdir -p /var/www/your_domain sudo rsync -a /home/your_user/sitio/ /var/www/your_domain/ ``` Asigna el propietario y el grupo a todo el árbol: ```bash sudo chown -R your_user:www-data /var/www/your_domain ``` Aplica `755` a los directorios y `644` a los archivos. Usar `find` evita dar permiso de ejecución a los archivos, algo que `chmod -R 755` haría con todos: ```bash sudo find /var/www/your_domain -type d -exec chmod 755 {} + sudo find /var/www/your_domain -type f -exec chmod 644 {} + ``` Da permiso de escritura a `www-data` solo en el directorio de subidas. En WordPress es `wp-content/uploads`: ```bash sudo chown -R www-data:www-data /var/www/your_domain/wp-content/uploads ``` Los archivos con credenciales, como `wp-config.php` o `.env`, no deben ser legibles por el resto de usuarios: ```bash sudo chmod 640 /var/www/your_domain/wp-config.php ``` Actualiza la directiva `root` del sitio en Nginx para que apunte a `/var/www/your_domain`, recarga (`sudo nginx -t && sudo systemctl reload nginx`) y comprueba el acceso: ```bash sudo -u www-data test -r /var/www/your_domain/index.php && echo "puede leer" curl -I https://your_domain/ ``` ```output puede leer HTTP/2 200 ``` ## Paso 5: Corregir los permisos de las claves SSH OpenSSH rechaza la autenticación por clave si el directorio personal, `~/.ssh` o `authorized_keys` pueden ser modificados por otros usuarios. El cliente solo ve que se le vuelve a pedir la contraseña o `Permission denied (publickey)`; el motivo real está en el registro del servidor: ```bash sudo journalctl -u ssh -n 30 --no-pager | grep -i 'bad ownership\|authentication refused' ``` ```output sshd[2210]: Authentication refused: bad ownership or modes for directory /home/your_user/.ssh ``` Aplica los permisos que exige OpenSSH desde una sesión del usuario afectado (por ejemplo, entrando con contraseña o desde otra cuenta con `sudo -i -u your_user`): ```bash chmod go-w ~ chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys ``` Si los archivos se crearon con `sudo` y pertenecen a `root`, devuélvelos antes a su usuario: ```bash sudo chown -R your_user:your_user /home/your_user/.ssh ``` En el equipo cliente, la clave privada también debe ser privada, o `ssh` se negará a usarla con el aviso `UNPROTECTED PRIVATE KEY FILE!`: ```bash chmod 600 ~/.ssh/id_ed25519 ``` Comprueba el resultado: ```bash ls -ld ~ ~/.ssh ~/.ssh/authorized_keys ``` ```output drwxr-x--- 5 your_user your_user 4096 Sep 25 10:30 /home/your_user drwx------ 2 your_user your_user 4096 Sep 25 10:30 /home/your_user/.ssh -rw------- 1 your_user your_user 102 Sep 25 10:30 /home/your_user/.ssh/authorized_keys ``` Antes de cerrar la sesión actual, abre una segunda terminal y confirma que puedes entrar con la clave. ## Paso 6: Compartir un directorio entre varios usuarios Cuando varios usuarios deben editar los mismos archivos, lo correcto es un grupo común y el bit setgid, no dar permisos a todo el mundo. Crea el grupo y añade a los usuarios: ```bash sudo groupadd equipo sudo usermod -aG equipo your_user sudo usermod -aG equipo other_user ``` Crea el directorio con el grupo `equipo` y permisos `2775`. El `2` inicial es el bit setgid: todo lo que se cree dentro pertenecerá al grupo `equipo`, sin importar quién lo cree: ```bash sudo mkdir -p /srv/proyecto sudo chown root:equipo /srv/proyecto sudo chmod 2775 /srv/proyecto ``` ```bash ls -ld /srv/proyecto ``` ```output drwxrwsr-x 2 root equipo 4096 Sep 25 10:40 /srv/proyecto ``` La `s` en la posición de ejecución del grupo confirma el setgid. Los archivos nuevos se crean con la máscara `umask` del usuario, que en Ubuntu es `002` para usuarios normales, así que el grupo podrá escribir en ellos. Compruébalo iniciando una sesión nueva como `other_user` (por SSH, o con `sudo -i -u other_user`) y creando un archivo: ```bash touch /srv/proyecto/prueba.txt ls -l /srv/proyecto/prueba.txt ``` ```output -rw-rw-r-- 1 other_user equipo 0 Sep 25 10:42 /srv/proyecto/prueba.txt ``` ## Paso 7: Dar acceso a un usuario concreto con ACL Los permisos clásicos solo admiten un propietario y un grupo. Si necesitas que un usuario más acceda a un directorio sin cambiar el grupo ni abrirlo a todos, usa listas de control de acceso (ACL). Instala las herramientas: ```bash sudo apt install acl ``` Por ejemplo, para que Nginx (`www-data`) pueda leer un directorio de informes que pertenece a `your_user`: ```bash sudo setfacl -R -m u:www-data:rX /srv/informes sudo setfacl -d -m u:www-data:rX /srv/informes ``` La `X` mayúscula da permiso de ejecución solo a los directorios (y a los archivos que ya lo tuvieran), y la opción `-d` define una ACL por defecto que heredarán los archivos nuevos. Consulta el resultado: ```bash getfacl /srv/informes ``` ```output # file: srv/informes # owner: your_user # group: your_user user::rwx user:www-data:r-x group::r-x mask::r-x other::--- default:user::rwx default:user:www-data:r-x default:group::r-x default:mask::r-x default:other::--- ``` Un `+` al final de los permisos en `ls -l` indica que el archivo tiene ACL. Para eliminar la entrada de un usuario, usa `sudo setfacl -R -x u:www-data /srv/informes`. ## Paso 8: Revisar los permisos de servicios y bases de datos Los servicios del sistema necesitan que sus archivos pertenezcan a su propio usuario. El caso típico es restaurar una copia de MySQL con `root` como propietario: el servicio no arranca y el registro muestra `Permission denied` o `errno 13`. Comprueba y corrige el propietario: ```bash sudo ls -ld /var/lib/mysql sudo chown -R mysql:mysql /var/lib/mysql sudo systemctl start mysql ``` Para cualquier servicio, consulta con qué usuario se ejecuta en su unidad de systemd y compáralo con el propietario de los archivos que usa: ```bash systemctl show -p User -p Group nombre_servicio ``` Si los permisos son correctos y el acceso sigue denegado, puede estar bloqueándolo AppArmor, que en Ubuntu restringe las rutas a las que acceden servicios como MySQL. Busca denegaciones en el registro del núcleo: ```bash sudo journalctl -k | grep 'apparmor="DENIED"' | tail -n 5 ``` ## Paso 9: Auditar permisos inseguros Una revisión periódica detecta archivos que cualquiera puede modificar o ejecutables con privilegios elevados. La opción `-xdev` limita la búsqueda al sistema de archivos raíz y evita recorrer `/proc`. Archivos que cualquier usuario puede modificar: ```bash sudo find / -xdev -type f -perm -0002 -ls ``` Directorios con escritura para todos y sin el bit sticky (cualquiera podría borrar archivos ajenos): ```bash sudo find / -xdev -type d -perm -0002 ! -perm -1000 -ls ``` Archivos sin propietario o grupo válido, normalmente restos de usuarios eliminados: ```bash sudo find / -xdev \( -nouser -o -nogroup \) -ls ``` Ejecutables con setuid o setgid: ```bash sudo find / -xdev -type f \( -perm -4000 -o -perm -2000 \) -ls ``` Guarda la última lista y compárala en revisiones futuras: un binario setuid nuevo fuera de los paquetes del sistema merece una investigación. ## Solución de problemas **`sudo: /etc/sudoers is world writable` o sudo deja de funcionar**: alguien cambió los permisos de `/etc/sudoers` y sudo se niega a usarlo. Arranca el servidor en modo de recuperación desde la consola del VPS y restaura los permisos con `chmod 0440 /etc/sudoers`. **Tras un `chmod -R 777` el sistema funciona mal**: no existe un comando para deshacerlo. Restaura desde una copia de seguridad o reaplica el esquema correcto directorio a directorio como en el paso 4; en rutas del sistema, reinstalar los paquetes afectados con `sudo apt install --reinstall` recupera sus permisos originales. **`Operation not permitted` incluso como root**: el archivo puede tener el atributo inmutable. Compruébalo con `lsattr archivo` (aparece una `i`) y quítalo con `sudo chattr -i archivo` si es intencionado. **El usuario ya está en el grupo pero sigue sin acceso**: la sesión o el servicio se iniciaron antes del cambio. Vuelve a iniciar sesión o reinicia el servicio. ## Conclusión Has aprendido a leer los permisos de toda una ruta con `namei -l`, a comprobar el acceso con el usuario que falla y a corregir los casos más comunes: scripts sin permiso de ejecución, sitios web servidos por `www-data`, claves SSH, directorios compartidos con setgid y accesos puntuales con ACL. Como siguientes pasos, revisa el `umask` de tus servicios, programa la auditoría del paso 9 de forma periódica y documenta el esquema de permisos de cada aplicación para aplicarlo igual en cada despliegue.