Ajustar PHP-FPM para mejor rendimiento
Dedicados & VPS
25

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_children procesos 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_servers y max_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.