Tutoriales de VPS
Sitio web en VPS devuelve 403 Forbidden (2026): lista de verificación de permisos de Nginx/Apache, index y SELinux
Cuando un sitio web en VPS conecta pero devuelve 403 Forbidden, normalmente no es un fallo de red, sino que el servidor web rechaza el acceso. Este artículo recorre paso a paso Nginx, Apache, permisos de directorio, archivos index, SELinux, proxy inverso y escenarios comunes de WordPress.

He visto a mucha gente que, en cuanto ve un 403, se pone a cambiar el DNS, reiniciar el servidor o incluso sospechar que el VPS está bloqueado. En realidad, 403 Forbidden no es lo mismo que "no se puede conectar".
Si el navegador puede abrir la página pero muestra 403 Forbidden, significa que la solicitud ya llegó a tu VPS y que Nginx o Apache la recibieron; simplemente decidieron que esa ruta no está permitida.
Las causas más comunes se agrupan en unas pocas categorías: el directorio no tiene archivo index, los permisos de archivo son incorrectos, el propietario del directorio del sitio es incorrecto, la configuración de Nginx/Apache contiene un deny, SELinux está bloqueando, o las reglas de WordPress o del panel están bloqueando la solicitud.
A continuación sigue el orden real de diagnóstico; no empieces cambiando permisos a lo loco.
Primero revisa el código de respuesta con curl:
curl -I https://example.com
Si ves algo como:
HTTP/1.1 403 Forbidden
Server: nginx
significa que el servicio web ya respondió; simplemente está rechazando el acceso.
Si en cambio ves:
404 Not Found: la ruta o el archivo no existe;502 Bad Gateway: algo detrás de Nginx como PHP-FPM, Node o Gunicorn está fallando;521/522: Cloudflare no pudo conectar con el origen o se agotó el tiempo de espera;403 Forbidden: céntrate en permisos, directorios, reglas y políticas de seguridad.
Esta distinción es importante. Con un 403 no se revisa primero la red, sino por qué el servidor web no permite el acceso.
Nginx:
sudo tail -n 80 /var/log/nginx/error.log
Apache:
sudo tail -n 80 /var/log/apache2/error.log
En CentOS / AlmaLinux / Rocky Linux, Apache puede ser:
sudo tail -n 80 /var/log/httpd/error_log
Las entradas típicas del registro se parecen a esto:
directory index of "/var/www/site/" is forbidden
O:
open() "/var/www/site/index.html" failed (13: Permission denied)
Estas dos significan cosas completamente distintas.
La primera es que el directorio no tiene archivo index y el servidor no permite listar directorios; la segunda es que el archivo existe pero el usuario del servidor web no tiene permiso para leerlo.
Muchos 403 ocurren porque accediste a un directorio que no tiene página de inicio predeterminada.
Mira el directorio del sitio:
ls -lah /var/www/site
Debería haber al menos uno de:
index.html
index.htm
index.php
La configuración de Nginx también debe ser correcta:
index index.html index.htm index.php;
En Apache, revisa DirectoryIndex:
DirectoryIndex index.html index.php
Si el directorio realmente no tiene archivo index, que Nginx devuelva 403 es normal. No es que no pueda abrir, es que no permite mostrar el listado completo del directorio a otros.
Para una prueba temporal, coloca un archivo:
echo 'ok' | sudo tee /var/www/site/index.html
Luego visita el sitio de nuevo. Si el 403 desaparece, el problema está en el archivo index o en la configuración de la raíz del sitio.
Mucha gente solo mira los permisos de index.html y pasa por alto los directorios superiores.
Para leer un archivo, el servidor web no solo necesita leer el archivo en sí, sino también poder entrar en los directorios superiores. Por ejemplo, con /var/www/site/index.html, cada nivel — /var, /var/www, /var/www/site — necesita permiso de ejecución.
Este comando es el más claro:
namei -om /var/www/site/index.html
Normalmente se ve más o menos así:
drwxr-xr-x root root /
drwxr-xr-x root root var
drwxr-xr-x root root www
drwxr-xr-x www-data www-data site
-rw-r--r-- www-data www-data index.html
Recomendaciones habituales:
sudo find /var/www/site -type d -exec chmod 755 {} \;
sudo find /var/www/site -type f -exec chmod 644 {} \;
No apliques chmod -R 777 a todo sin pensar. Puede que haga desaparecer el 403, pero también acaba con la seguridad.
En Ubuntu / Debian, los usuarios habituales de Nginx y Apache son www-data. Puedes establecer el propietario así:
sudo chown -R www-data:www-data /var/www/site
En CentOS / AlmaLinux / Rocky Linux, el usuario habitual de Apache es apache, y el de Nginx puede ser nginx:
sudo chown -R nginx:nginx /var/www/site
Si no estás seguro de quién es el usuario, revisa los procesos:
ps aux | grep -E 'nginx|apache|httpd'
Muchos 403 de Nginx no son por permisos de Linux, sino porque la configuración directamente prohíbe el acceso.
Primero prueba la configuración:
sudo nginx -t
Luego mira la configuración del sitio:
sudo nginx -T | grep -nE 'server_name|root|location|deny|allow|try_files|autoindex'
Céntrate en esto:
location / {
try_files $uri $uri/ =404;
}
Si una solicitud a / coincide con un directorio que no tiene archivo index, puede aparecer directory index is forbidden.
Busca también reglas como:
deny all;
O un location que bloquee un directorio:
location /uploads/ {
deny all;
}
Si el 403 solo ocurre en una ruta concreta, como /admin/, /uploads/ o /.well-known/, céntrate en el location correspondiente.
Después de cambiar la configuración:
sudo nginx -t
sudo systemctl reload nginx
Los 403 de Apache suelen aparecer en estos puntos.
El directorio del sitio debe permitir el acceso:
<Directory /var/www/site>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Si ves:
Require all denied
queda bastante claro: está denegando el acceso.
También está .htaccess. Tras migrar WordPress, Laravel o un proyecto antiguo, .htaccess puede desordenar fácilmente las reglas de rutas.
Puedes renombrarlo temporalmente para probar:
sudo mv /var/www/site/.htaccess /var/www/site/.htaccess.bak
sudo systemctl reload apache2
Si el 403 desaparece, el problema está en .htaccess. No lo borres a la ligera; vuelve a añadir las reglas poco a poco.
Prueba de configuración de Apache:
sudo apachectl configtest
Recarga en Ubuntu / Debian:
sudo systemctl reload apache2
Familia CentOS:
sudo systemctl reload httpd
Si usas Rocky Linux, AlmaLinux o CentOS Stream, los permisos parecen correctos pero sigues recibiendo 403, es muy probable que sea SELinux.
Primero mira el estado:
getenforce
Si devuelve:
Enforcing
entonces revisa el contexto:
ls -Z /var/www/site
El contenido web normalmente necesita un contexto como httpd_sys_content_t.
Solución habitual:
sudo restorecon -Rv /var/www/site
Si el directorio de tu sitio no está en una ubicación estándar — por ejemplo, bajo /home/deploy/site — necesitas establecer el contexto aparte. No desactives SELinux como solución permanente. Para verificar temporalmente puedes usar:
sudo setenforce 0
Si el 403 desaparece inmediatamente al desactivarlo, vas por buen camino. Recuerda restaurarlo después de verificar:
sudo setenforce 1
Luego resuélvelo con el contexto o boolean correctos.
Si usas WordPress, un 403 también puede venir de plugins, reglas de firewall o enlaces permanentes.
Prueba en este orden:
- Renombra temporalmente el directorio del plugin de seguridad;
- Regenera los enlaces permanentes;
- Revisa
.htaccesso las reglas de reescritura de Nginx; - Revisa los permisos de
wp-content/uploads; - Mira el registro de errores del servidor web, no solo la página del navegador.
Los usuarios de BT Panel también deben revisar:
- Si el directorio del sitio está mal elegido;
- Si la protección contra hotlinking bloquea por error;
- Si las reglas de reescritura de URL coinciden mal;
- Si un WAF o plugin de seguridad está bloqueando;
- Si la raíz del sitio tiene
index.htmloindex.php.
Los paneles reducen la barrera de operación, pero las causas raíz del 403 siguen siendo las mismas categorías: directorios, permisos, reglas y políticas de seguridad.
| Síntoma | Causa más probable | Qué revisar primero |
|---|---|---|
| Página de inicio 403, el registro dice directory index is forbidden | No hay archivo index | ls -lah, configuración de index de Nginx/Apache |
| El registro dice Permission denied | Permisos insuficientes del archivo o del directorio superior | namei -om, owner, chmod |
| Solo un directorio devuelve 403 | Bloqueo por location / .htaccess | Nginx location, Apache Directory, .htaccess |
| En CentOS los permisos están bien pero sigue el 403 | Contexto SELinux incorrecto | getenforce, ls -Z, restorecon |
| Panel de WordPress o directorio de subidas 403 | Plugin/WAF/reescritura/permisos de directorio | Plugins, .htaccess, permisos de uploads |
| 403 mostrado detrás de Cloudflare | Bloqueo del origen o de reglas de Cloudflare | Registros del origen, WAF, reglas de firewall |
Cuando realmente me encuentro con un 403, por lo general no reinstalo el entorno primero, ni cambio a 777 de inmediato.
Sigo este orden:
curl -I https://example.com
sudo tail -n 80 /var/log/nginx/error.log
ls -lah /var/www/site
namei -om /var/www/site/index.html
sudo nginx -T | grep -nE 'root|index|location|deny|try_files'
Si es Apache, cambio a:
sudo tail -n 80 /var/log/apache2/error.log
sudo apachectl configtest
grep -R "Require all" /etc/apache2/sites-enabled /etc/apache2/apache2.conf
En la familia CentOS, añado:
getenforce
ls -Z /var/www/site
Siguiendo este orden, normalmente puedo identificar en qué capa está el problema en unos diez minutos.
403 Forbidden se malinterpreta fácilmente como "el sitio está caído". En realidad, suele ser una buena noticia: la solicitud ya llegó al VPS, el servicio web está vivo y solo es alguna regla o permiso que no le deja leer el archivo.
No reinstales Nginx, reinicies el VPS ni cambies el DNS de inmediato. Primero mira el registro de errores, luego revisa index, permisos, configuración y SELinux. Mientras en el registro aparezca directory index is forbidden o Permission denied, la dirección está clara.