Situación actual: PHP2Shell. Dos vulnerabilidades críticas de PHP (CVSS 9.2) permiten ejecutar código malicioso sin autenticación. Parches desde el 21/10/2026.Qué hacer ahora →

Configurar Nginx para PHP de forma segura

La mayoría de los puntos débiles de las configuraciones de Nginx para PHP no están en Nginx, sino en unas pocas líneas de la location de PHP. Cómo configurar el traspaso a PHP-FPM para que solo se ejecuten los scripts deseados.

Actualizado 7 min de lecturaRefuerzo y configuración

En resumen: para configurar Nginx con PHP de forma segura, pase a PHP-FPM solo los scripts que realmente existen y, en aplicaciones con front controller, únicamente el index.php. A ello se suman dotfiles bloqueados como .git y .env, un servidor por defecto para nombres de host desconocidos, límites de tamaño adecuados y security.limit_extensions = .php en el pool. Eso no protege de vulnerabilidades del propio PHP, pero limita lo que puede ejecutarse tras un fallo.

Las líneas más peligrosas están en la location de PHP

Desde PHP2Shell, muchos equipos revisan sus versiones y pools de PHP-FPM, como describe la página Proteger Nginx con PHP-FPM, y tras la actualización reinician todos los workers. Una segunda mirada corresponde a la propia configuración de Nginx. Allí se decide qué archivos se ejecutan en absoluto como PHP.

En muchas configuraciones hay un bloque que pasa a PHP-FPM cualquier petición a .php, esté donde esté el archivo. Si un archivo PHP inyectado acaba en una carpeta de subidas, el servidor lo ejecuta. Así, de un fallo de archivos surge una puerta trasera.

Este artículo se centra en el lado de Nginx: qué directivas cuentan, cómo actúa el orden de los bloques location y cómo probar el resultado.

Cómo decide Nginx qué bloque se aplica

Quien quiera configurar Nginx con PHP de forma segura debe conocer la selección de los bloques location. Según la documentación de Nginx, funciona así:

  1. Una coincidencia exacta con location = termina la búsqueda de inmediato.
  2. Entre las location de prefijo se recuerda la coincidente más larga. Si lleva ^~, ya no se comprueban expresiones regulares.
  3. En caso contrario, se comprueban las expresiones regulares (~, ~*) en el orden del archivo de configuración; gana la primera coincidencia.
  4. Si ninguna expresión regular coincide, rige la location de prefijo recordada.

De aquí se derivan dos reglas prácticas. Un bloqueo de PHP en carpetas de subidas debe crearse como prefijo ^~ o como expresión regular antes del bloque general de PHP. Y una location de prefijo normal como location /uploads/ no protege, porque la expresión regular para .php la pasa por alto.

Una configuración básica segura

El ejemplo siguiente muestra un bloque server para una aplicación con front controller, como es habitual en Laravel, Symfony, Shopware 6 o muchos desarrollos propios. Adapte las rutas, el socket y los certificados.

server {
    listen 443 ssl;
    server_name www.example.de;
    root /var/www/seite1/public;
    index index.php;

    ssl_certificate     /etc/ssl/seite1/fullchain.pem;
    ssl_certificate_key /etc/ssl/seite1/privkey.pem;

    server_tokens off;
    client_max_body_size 32m;

    # Permitir Let's Encrypt y otras rutas conocidas
    location ^~ /.well-known/ {
        try_files $uri =404;
    }

    # Bloquear archivos y carpetas ocultos (.git, .env, .htaccess)
    location ~ /\. {
        deny all;
    }

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Solo el front controller se pasa a PHP-FPM
    location = /index.php {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_hide_header X-Powered-By;
        fastcgi_pass unix:/run/php/seite1.sock;
    }

    # Cualquier otro archivo PHP no se ejecuta
    location ~ \.php$ {
        return 404;
    }
}

$realpath_root resuelve los enlaces simbólicos. Esto es importante en despliegues con un enlace simbólico cambiante hacia la versión actual, para que PHP-FPM y OPcache vean la ruta correcta. Tenga en cuenta además: según la documentación de Nginx, las directivas fastcgi_param solo se heredan de niveles superiores si en el nivel actual no hay ninguna propia. Por eso include fastcgi_params; pertenece al mismo bloque.

Los CMS clásicos como WordPress, TYPO3 o Contao tienen varios puntos de entrada. En ellos sustituya el bloque del front controller por una location general de PHP que solo pase archivos existentes (try_files $uri =404;) y bloquee la ejecución en todas las carpetas con permiso de escritura. Cómo se logra figura en Prohibir la ejecución de PHP en las carpetas de subidas.

La segunda protección en PHP-FPM

Nginx decide qué se pasa; PHP-FPM decide qué ejecuta. Según el manual de PHP, PHP-FPM ejecuta por defecto archivos con .php y .phar y recomienda por sí mismo limitarlo a .php. Esto compensa errores de configuración en el servidor web.

; en el pool, p. ej. /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

El socket solo debería ser accesible para Nginx. Los puertos de FPM en la red, como 9000, no deben abrirse hacia fuera. Cómo hace el servidor para mostrar en conjunto solo los puertos necesarios lo describe Cortafuegos para servidores web: abrir solo los puertos necesarios.

Nombres de host desconocidos y otros tornillos de ajuste

Sin un servidor por defecto propio, Nginx responde a las peticiones a nombres de host desconocidos con el primer bloque server coincidente. Los escaneos automatizados que solo se dirigen a la dirección IP acaban entonces directamente en su aplicación. Un servidor por defecto propio termina esas peticiones sin respuesta.

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
    return 444;
}

Otros puntos que han dado buen resultado:

Ajuste Recomendación Finalidad
server_tokens off ningún número de versión en cabeceras ni páginas de error
client_max_body_size acorde con post_max_size rechazar pronto las peticiones grandes
autoindex desactivado (valor por defecto) sin listados de directorios
fastcgi_hide_header X-Powered-By no mostrar la versión de PHP hacia fuera
Páginas de estado pm.status_path solo interno no publicar datos de funcionamiento
Archivos de copia de seguridad bloquear o eliminar .sql, .zip, .bak en el webroot evitar la descarga de bases de datos

Más sobre los datos de versión figura en el artículo expose_php y cabecera Server.

Otro ajuste afecta a los métodos HTTP permitidos. La mayoría de los sitios web solo necesitan GET, HEAD y POST. Con limit_except pueden rechazarse otros métodos en una location; según la documentación de Nginx, permitir GET permite automáticamente también HEAD. Compruebe antes si las interfaces de su aplicación usan, por ejemplo, PUT o DELETE, porque las API REST lo hacen con frecuencia.

Probar antes de recargar

Compruebe cada cambio primero con nginx -t y recargue Nginx solo después. A continuación, pruebe el comportamiento desde fuera con peticiones normales a su propio dominio:

sudo nginx -t && sudo systemctl reload nginx
# Se espera: 403 o 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env
# Se espera: 404, porque solo se ejecuta el front controller
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# ¿Qué bloques pasan a PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"

Antes de cada cambio importante, guarde con fecha la salida completa de nginx -T. Contiene toda la configuración efectiva, incluidos todos los archivos incluidos. Si algo sale mal tras un cambio, la comparación muestra de inmediato qué difiere. Con la próxima vulnerabilidad crítica tendrá además una base fiable para el inventario, sin tener que reunir archivos primero.

Consejo

Cambie la configuración primero en un entorno de pruebas o en una copia del bloque server. Un punto de entrada olvidado, por ejemplo una devolución de llamada de pagos, solo se descubre cuando dejan de llegar pedidos.

¿Cómo ayuda PHP SOS en concreto?

  • Leer la configuración: analizamos toda la configuración de Nginx con nginx -T y asignamos cada traspaso a PHP a su sitio web y su pool.
  • Definir los puntos de entrada: junto con sus desarrolladores determinamos qué scripts deben ejecutarse y bloqueamos el resto.
  • Aplicar y probar: adaptamos bloques server y pools, comprobamos con nginx -t y probamos formularios, vías de pago y subidas.
  • Asegurarlo de forma duradera: la configuración pasa a formar parte de nuestro refuerzo de servidores y de la documentación de su servidor.

Preguntas frecuentes

¿Hay que reiniciar Nginx tras una actualización de PHP?

Para el parche de PHP no, porque Nginx no contiene PHP. Hay que reiniciar todos los servicios de PHP-FPM. Si además cambia la configuración de Nginx, compruébela antes con nginx -t y recargue Nginx a continuación.

¿Por qué pasar a PHP solo index.php?

Muchas aplicaciones modernas tienen un único punto de entrada, el front controller. Si solo se pasa ese archivo a PHP-FPM, un archivo PHP inyectado en otro lugar no puede ejecutarse desde el navegador. En sistemas con muchos puntos de entrada, este patrón no es posible.

¿Qué aporta security.limit_extensions en PHP-FPM?

El ajuste determina qué extensiones de archivo ejecuta PHP-FPM como script. Según el manual de PHP, el valor por defecto es .php .phar; se recomienda limitarlo a .php. Esto compensa errores en la configuración del servidor web, pero no la sustituye.

¿Son las reglas de Nginx una protección frente a PHP2Shell?

No. PHP2Shell reside en el intérprete de PHP y solo se cierra con la actualización a una versión corregida y el reinicio de todos los workers. Una configuración segura de Nginx reduce la superficie de ataque y limita el daño tras una intrusión.

Fuentes

Contacto inmediato

Cada hora cuenta. Escríbanos ahora.

Describa brevemente el sistema, la versión de PHP y lo que ha observado. Nos pondremos en contacto, aclararemos la situación y trabajaremos en remoto hasta que el incidente quede cerrado y documentado.

Ayuda inmediata