Qué es PHP-FPM
PHP-FPM (FastCGI Process Manager) es la forma moderna de ejecutar PHP en un servidor. En lugar de ser un módulo cargado dentro del servidor web (como mod_php), corre como un proceso independiente al que el servidor web le envía las peticiones por FastCGI. Esto trae ventajas importantes:
- Menor consumo de memoria — solo se mantienen los workers que realmente se usan.
- Cada pool de PHP-FPM puede tener su propia configuración, usuario, límites.
- Reciclado automático de procesos para liberar memoria.
- Ejecución paralela con Nginx, que por sí solo no corre PHP.
Ubicación de los archivos
En la mayoría de distribuciones encuentras:
- Configuración global:
/etc/php/8.x/fpm/php-fpm.conf - Pools:
/etc/php/8.x/fpm/pool.d/www.conf - php.ini de FPM:
/etc/php/8.x/fpm/php.ini
En CentOS/Rocky la ruta típica es /etc/php-fpm.d/. En cPanel con EasyApache y Select PHP Version la ruta depende de la versión instalada.
Los parámetros que importan
La sección clave es el process manager. Un pool básico tiene estas líneas:
pm = dynamic pm.max_children = 50 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 15 pm.max_requests = 500
pm (modo)
- static — siempre mantiene exactamente
pm.max_childrenprocesos activos. Predecible y veloz bajo carga constante pero gasta RAM cuando no hay tráfico. - dynamic — ajusta el número de procesos según la carga, entre
min_spare_serversymax_spare_servers. Es el más usado. - ondemand — solo crea procesos cuando llegan peticiones, los mata después. Usa mínima RAM cuando no hay tráfico, pero añade latencia al crear procesos nuevos. Ideal para sitios con poco tráfico.
pm.max_children
El número máximo de procesos PHP simultáneos. Es el parámetro más crítico: si es muy bajo, las peticiones esperan en cola; si es muy alto, te quedas sin RAM y el servidor empieza a swapping.
Regla rápida para calcularlo:
pm.max_children = (RAM disponible para PHP) / (RAM promedio por proceso)
Para saber cuánta RAM usa cada proceso PHP en promedio, ejecuta:
ps -ylC php-fpm8.2 --sort:rss
Mira la columna RSS (en KB). Divide el tamaño promedio entre 1024 para obtener MB. Si cada proceso usa 80 MB y reservas 4 GB para PHP, puedes correr aproximadamente 50 children.
pm.start_servers
Cuántos workers arrancan al iniciar el servicio. Debe ser el promedio entre min_spare_servers y max_spare_servers.
pm.min_spare_servers / pm.max_spare_servers
PHP-FPM mantiene siempre entre estos dos números de workers "en espera" listos para atender. Si bajan de min_spare crea nuevos; si suben de max_spare los mata. Valores razonables: 20-30% del total de children para cada uno.
pm.max_requests
Cuántas peticiones atiende cada worker antes de reciclarse (morirse y renacer fresco). Protege contra memory leaks — si un proceso PHP acumula memoria por alguna extensión defectuosa, al morir libera todo. Valores típicos: 200-1000. Sin esto, procesos de larga duración pueden crecer indefinidamente.
Ejemplo para distintos tamaños de servidor
VPS con 2 GB de RAM (sitio WordPress medio)
pm = dynamic pm.max_children = 20 pm.start_servers = 5 pm.min_spare_servers = 3 pm.max_spare_servers = 10 pm.max_requests = 500
VPS con 4 GB de RAM (WordPress más cargado)
pm = dynamic pm.max_children = 40 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 15 pm.max_requests = 500
VPS con 8 GB (tienda WooCommerce activa)
pm = dynamic pm.max_children = 80 pm.start_servers = 20 pm.min_spare_servers = 10 pm.max_spare_servers = 30 pm.max_requests = 500
VPS con poco tráfico (blog personal)
pm = ondemand pm.max_children = 10 pm.process_idle_timeout = 30s pm.max_requests = 500
Ajustes adicionales recomendados
opcache habilitado
En php.ini verifica que OPcache está activo:
opcache.enable = 1 opcache.memory_consumption = 128 opcache.max_accelerated_files = 10000 opcache.validate_timestamps = 1 opcache.revalidate_freq = 60
OPcache guarda el bytecode de PHP compilado en memoria para evitar recompilarlo en cada petición. Puede duplicar el rendimiento fácilmente.
Memory limit realista
memory_limit = 256M
WordPress con muchos plugins puede necesitar 256 MB. Menos puede dar errores de "Allowed memory size exhausted". Pero tampoco exageres — un memory_limit gigante permite que procesos rebeldes consuman toda tu RAM.
Realpath cache
realpath_cache_size = 4096K realpath_cache_ttl = 600
Cachea las rutas de archivos resueltas, muy útil para CMS con muchas includes.
Monitorear el estado en tiempo real
PHP-FPM expone un endpoint de estado que puedes consultar. Habilítalo en tu pool:
pm.status_path = /fpm-status ping.path = /fpm-ping
Y permítelo en tu servidor web. Luego consultando /fpm-status?full ves:
- Procesos activos, en espera, totales.
- Peticiones aceptadas.
- Cola de espera.
- Tiempo de ejecución de cada worker.
Si la "listen queue" nunca es cero, necesitas más max_children. Si los spare servers nunca llegan a max_spare, puedes bajarlo para ahorrar RAM.
Después de cambiar configuración
Recarga PHP-FPM para aplicar cambios:
sudo systemctl reload php8.2-fpm
Verifica que esté corriendo:
sudo systemctl status php8.2-fpm
Si falla, revisa los logs:
sudo tail -50 /var/log/php8.2-fpm.log
Señales de que tu config está mal
"504 Gateway Timeout" frecuentes
Los workers están saturados. Sube max_children si tienes RAM, o revisa por qué los procesos tardan tanto (consultas lentas de MySQL, loops ineficientes).
Servidor consume 100% de RAM y va a swap
max_children muy alto para la RAM disponible. Bájalo o aumenta RAM.
Primera carga de página lenta tras inactividad
Si usas pm = ondemand, es normal — los procesos se crean al primer hit. Cambia a dynamic con min_spare_servers razonable.
Errores "pool seems busy"
La cola de peticiones está llena. Sube listen.backlog temporalmente y diagnostica por qué hay tanta carga.