En resumen: PHP-FPM (FastCGI Process Manager) ejecuta PHP como servicio propio junto al servidor web. Un proceso maestro gestiona pools y cada pool inicia workers que atienden las peticiones mediante FastCGI. Los pools pueden operar para cada sitio web con su propio usuario, sus propios límites y ajustes de PHP bloqueados. Como los workers atienden muchas peticiones seguidas, tras una actualización de PHP deben reiniciarse todos.
¿Qué es PHP-FPM?
El manual de PHP describe FPM como la implementación FastCGI principal de PHP, con funciones útiles sobre todo para sitios web con mucha carga. FPM se incorporó con PHP 5.3.3 como SAPI propia, es decir, como modo de ejecución propio. Su nombre de SAPI es fpm-fcgi.
La diferencia con mod_php: PHP no se ejecuta dentro del servidor web, sino como servicio propio. Nginx, Apache u otro servidor web pasa las peticiones PHP mediante el protocolo FastCGI y recibe la respuesta ya terminada. Así, el servidor web y PHP pueden reiniciarse, configurarse y protegerse de forma independiente. Cómo funciona FastCGI en general se explica en CGI y FastCGI.
Maestro, pools y workers: el modelo de procesos
PHP-FPM consta de tres niveles:
- Proceso maestro: lee la configuración, abre los sockets e inicia o finaliza workers. Él mismo no ejecuta código de aplicación.
- Pools: cada pool tiene un nombre, un socket o puerto propio, un usuario Unix propio y ajustes de PHP propios. El manual menciona expresamente uid, gid, chroot, entorno y php.ini distintos para cada pool.
- Workers: procesos de un pool que aceptan y ejecutan peticiones. Un worker atiende muchas peticiones seguidas antes de ser sustituido.
Cuántos workers se ejecutan lo determina el gestor de procesos con la directiva pm:
| Modo | Comportamiento | Directivas importantes |
|---|---|---|
static |
número fijo de workers | pm.max_children |
dynamic |
workers entre un límite inferior y uno superior | pm.start_servers, pm.min_spare_servers, pm.max_spare_servers |
ondemand |
workers solo cuando hacen falta, se eliminan tras un tiempo de inactividad | pm.process_idle_timeout (por defecto 10s) |
pm.max_children limita en todos los modos el número de peticiones simultáneas. pm.max_requests sustituye un worker tras un número fijo de peticiones; el valor por defecto 0 significa sin límite.
Qué modo conviene depende de la carga. static mantiene siempre el mismo número de workers disponibles y es adecuado para aplicaciones con un uso intenso y uniforme y suficiente memoria RAM. dynamic es un compromiso para la mayoría de los sitios web. ondemand ahorra memoria en servidores con muchos sitios pequeños, porque los pools sin visitantes no ocupan workers; a cambio, la primera petición tras una pausa tarda algo más. Un pm.max_children demasiado alto puede llevar al servidor a la falta de memoria en los picos de carga; uno demasiado bajo provoca tiempos de espera y mensajes de error del servidor web.
Un pool con ajustes básicos seguros
Un ejemplo de pool propio para cada sitio web, con directivas del manual de PHP. Las rutas y los valores son ejemplos:
; /etc/php/8.3/fpm/pool.d/kunde-a.conf
[kunde-a]
user = kunde-a
group = kunde-a
listen = /run/php/kunde-a.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
request_terminate_timeout = 60s
security.limit_extensions = .php
clear_env = yes
php_admin_value[open_basedir] = /var/www/kunde-a:/tmp
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[error_log] = /var/log/php/kunde-a.error.log
Según el manual, los valores fijados con php_value y php_flag pueden modificarse en tiempo de ejecución con ini_set(), mientras que los fijados con php_admin_value y php_admin_flag no. security.limit_extensions tiene por defecto .php .phar y determina qué extensiones de archivo ejecuta FPM como script principal. clear_env = yes es el valor por defecto y vacía el entorno de los workers.
Para la supervisión hay una página de estado mediante pm.status_path y una página de ping mediante ping.path. Ambas solo deberían ser accesibles internamente. FPM registra las peticiones lentas con backtrace cuando se fijan request_slowlog_timeout y slowlog.
El manual de PHP advierte: quien pueda abrir una conexión FastCGI con PHP-FPM controla la configuración de la petición y, con ello, puede ejecutar código arbitrario. PHP-FPM nunca debe ser accesible desde una red no fiable. Utilice un socket Unix o listen.allowed_clients.
¿Qué papel desempeña PHP-FPM en PHP2Shell?
PHP-FPM se cuenta entre los modos de ejecución afectados. El modelo de procesos se hace especialmente patente en CVE-2026-109619: el estado interno de una petición puede persistir tras liberar la memoria, y una petición posterior en el mismo worker puede utilizarlo antes de que se restablezca. Esto solo es posible porque los workers atienden muchas peticiones seguidas.
De ello se derivan tres obligaciones:
- Instalar la actualización: PHP 8.5.12, 8.4.27, 8.3.36 o 8.2.35, o un backport confirmado de la distribución.
- Reiniciar todos los workers: los archivos nuevos en el disco no cambian nada mientras haya workers antiguos en ejecución. Esto vale para cada versión de FPM instalada y cada pool. Los comandos están en Reiniciar PHP-FPM y todos los workers.
- Fijar los valores provisionales de forma bloqueada: las medidas de php.net, como
session.upload_progress.enabled=0, pertenecen al pool mediantephp_admin_valueophp_admin_flag, no a.user.ini.
La separación en pools no sustituye una actualización, pero limita el daño: si cada sitio web se ejecuta con su propio usuario, tras una intrusión el atacante no alcanza automáticamente los archivos de los demás. Cómo es esto en concreto lo describe Aislar los pools de PHP-FPM por sitio web; la integración en Nginx está en Proteger Nginx con PHP-FPM.
¿Cómo ayuda PHP SOS en concreto?
- Inventariar los pools: listamos todas las versiones de FPM, pools, usuarios y sockets de su servidor.
- Parchear y reiniciar: actualizamos PHP y demostramos mediante las horas de inicio que ya no queda ningún worker antiguo.
- Separar los pools: en el marco del refuerzo del servidor configuramos para cada sitio web un pool con usuario propio y ajustes bloqueados.
- Comprobar la accesibilidad: verificamos que los sockets FastCGI y las páginas de estado no sean accesibles desde fuera.
Preguntas frecuentes
¿Qué significa FPM?
FPM significa FastCGI Process Manager. El manual de PHP lo describe como la implementación FastCGI principal de PHP, con funciones útiles sobre todo para sitios web con mucha carga. Se incorporó con PHP 5.3.3.
¿Cuál es la diferencia entre pool y worker?
Un pool es un grupo de procesos worker con configuración común: usuario, socket, límites y ajustes de PHP. Un worker es un proceso individual que atiende peticiones una tras otra. Un servidor puede tener muchos pools, por ejemplo uno por cada sitio web.
¿Debe ser accesible PHP-FPM por TCP o por un socket Unix?
Si el servidor web se ejecuta en el mismo host, el manual de PHP recomienda un socket Unix. Con TCP hay que fijar listen.allowed_clients, porque si no cualquier dirección puede conectarse. Según el manual, un puerto FastCGI accesible abiertamente permite ejecutar código arbitrario.
¿Protege pm.max_requests frente a vulnerabilidades como PHP2Shell?
No. pm.max_requests sustituye un worker tras un número fijo de peticiones y ayuda sobre todo contra las fugas de memoria en extensiones. Frente a una vulnerabilidad del intérprete solo ayuda la actualización con el posterior reinicio de todos los workers.