--- title: "Cómo optimizar los pools de PHP-FPM en Ubuntu 24.04" description: "Calcula pm.max_children según tu RAM, elige entre dynamic, ondemand y static, activa la página de estado y el slowlog de PHP-FPM 8.3 en Ubuntu 24.04." category: "Optimización de Rendimiento" language: es source: https://cubepath.com/es/docs/optimización-de-rendimiento/optimizacion-de-php-fpm-configuracion-de-pool updated: 2026-09-25 --- # Cómo optimizar los pools de PHP-FPM en Ubuntu 24.04 PHP-FPM ejecuta el código PHP en un conjunto de procesos (pool) que el servidor web, Nginx o Apache, llama a través de FastCGI. El tamaño de ese pool decide cuántas peticiones PHP se atienden a la vez: si es pequeño, las peticiones se quedan en cola y la web va lenta; si es demasiado grande, el servidor se queda sin memoria y empieza a usar swap o el kernel mata procesos. En este tutorial calcularás el tamaño correcto del pool de PHP-FPM 8.3 en Ubuntu 24.04 a partir de la memoria real que consumen tus procesos, elegirás el gestor de procesos adecuado y activarás las herramientas para comprobar que la configuración funciona bajo carga. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo`. - PHP 8.3 con PHP-FPM instalado (`sudo apt install php8.3-fpm`) y un servidor web que ya sirva tu aplicación PHP a través del socket `/run/php/php8.3-fpm.sock`. - La aplicación funcionando y recibiendo tráfico real o de prueba, para poder medir cuánta memoria usan los procesos. ## Paso 1: Revisar la configuración actual del pool Cada pool se define en un fichero dentro de `/etc/php/8.3/fpm/pool.d/`. Ubuntu instala uno llamado `www` en `www.conf`. Muestra sus directivas activas del gestor de procesos: ```bash grep -E '^(user|group|listen|pm)' /etc/php/8.3/fpm/pool.d/www.conf ``` ```output user = www-data group = www-data listen = /run/php/php8.3-fpm.sock listen.owner = www-data listen.group = www-data pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 ``` Con `pm.max_children = 5` el pool atiende como máximo cinco peticiones PHP simultáneas. Es un valor pensado para máquinas mínimas y casi siempre se queda corto. Comprueba también si ya se ha alcanzado ese límite: ```bash sudo grep 'max_children' /var/log/php8.3-fpm.log ``` ```output [25-Sep-2026 10:41:12] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it ``` Si ves este aviso, las peticiones se han quedado esperando un proceso libre. ## Paso 2: Medir la memoria de cada proceso PHP-FPM El valor de `pm.max_children` sale de dividir la memoria que puedes dedicar a PHP entre lo que ocupa cada proceso. Con la aplicación recibiendo tráfico, calcula la memoria media (RSS) de los procesos `php-fpm8.3`: ```bash ps --no-headers -o rss -C php-fpm8.3 | awk '{s+=$1} END {printf "%d procesos, media %.0f MB\n", NR, s/NR/1024}' ``` ```output 6 procesos, media 58 MB ``` La cifra incluye al proceso maestro, que ocupa poco, así que la media real de los workers es algo mayor. Mide varias veces a lo largo del día y quédate con el valor más alto. Una web WordPress típica ronda los 40-80 MB por proceso; aplicaciones Laravel o Magento pueden superar los 100 MB. Después, mira la memoria total y la que usan los demás servicios: ```bash free -m ``` ```output total used free shared buff/cache available Mem: 3915 1210 512 45 2193 2402 Swap: 0 0 0 ``` ## Paso 3: Calcular pm.max_children La fórmula es: ```text pm.max_children = (RAM total - RAM para el resto de servicios) / RAM media por proceso ``` Ejemplo con un servidor de 4 GB en el que MySQL, Nginx, Redis y el sistema necesitan unos 1.500 MB: ```text (4000 - 1500) / 60 = 41 -> pm.max_children = 40 ``` Redondea hacia abajo y deja margen: los procesos crecen con peticiones pesadas. Si el servidor solo ejecuta PHP-FPM y un Nginx, puedes reservar menos memoria para otros servicios, pero nunca asignes el 100 % de la RAM. ## Paso 4: Elegir el gestor de procesos La directiva `pm` define cómo se crean los procesos: | Modo | Comportamiento | Cuándo usarlo | |------|----------------|---------------| | `dynamic` | Mantiene un número de procesos en espera entre `pm.min_spare_servers` y `pm.max_spare_servers`, hasta `pm.max_children` | Opción por defecto, válida para la mayoría de servidores | | `ondemand` | No mantiene procesos en espera; los crea al llegar peticiones y los cierra tras `pm.process_idle_timeout` | Servidores con poca RAM o muchos pools con poco tráfico | | `static` | Mantiene siempre `pm.max_children` procesos | Servidores dedicados a una aplicación con tráfico alto y constante | `ondemand` ahorra memoria pero añade la latencia de crear un proceso a la primera petición tras un periodo inactivo. `static` elimina esa latencia a cambio de ocupar la memoria de forma permanente. ## Paso 5: Aplicar la nueva configuración Abre el fichero del pool: ```bash sudo nano /etc/php/8.3/fpm/pool.d/www.conf ``` Localiza las directivas `pm` y ajústalas. Este es un ejemplo con `dynamic` para el servidor de 4 GB del paso 3: ```ini pm = dynamic pm.max_children = 40 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 15 pm.max_requests = 500 ``` Una regla práctica para `dynamic` es poner `pm.start_servers` en torno al 25 % de `pm.max_children`, `pm.min_spare_servers` al 10-15 % y `pm.max_spare_servers` al 35-40 %. `pm.start_servers` debe estar entre el mínimo y el máximo de procesos en espera, o PHP-FPM no arrancará. `pm.max_requests` recicla cada proceso tras atender 500 peticiones, lo que contiene fugas de memoria de extensiones o de la propia aplicación. Con `0` los procesos no se reciclan nunca. Si prefieres `ondemand`, la configuración equivalente es: ```ini pm = ondemand pm.max_children = 40 pm.process_idle_timeout = 10s pm.max_requests = 500 ``` Comprueba la sintaxis antes de aplicar nada: ```bash sudo php-fpm8.3 -t ``` ```output [25-Sep-2026 11:02:31] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful ``` Recarga el servicio. `reload` reinicia los workers de forma ordenada sin cortar las peticiones en curso: ```bash sudo systemctl reload php8.3-fpm ``` ## Paso 6: Limitar la duración de las peticiones y activar el slowlog Una petición bloqueada (una consulta lenta, una API externa que no responde) ocupa un proceso indefinidamente. Añade estas líneas al final de `www.conf` para cortar las peticiones que superen 60 segundos y registrar la traza de las que tarden más de 5: ```ini request_terminate_timeout = 60s request_slowlog_timeout = 5s slowlog = /var/log/php8.3-fpm-slow.log ``` `request_terminate_timeout` debe ser igual o mayor que el `max_execution_time` de PHP y que el timeout de tu servidor web (`fastcgi_read_timeout` en Nginx), o los errores serán confusos. Comprueba la sintaxis y recarga: ```bash sudo php-fpm8.3 -t && sudo systemctl reload php8.3-fpm ``` Cuando una petición supere los 5 segundos, verás en el slowlog la pila de llamadas que indica dónde estaba el script: ```bash sudo tail -n 20 /var/log/php8.3-fpm-slow.log ``` ```output [25-Sep-2026 11:20:04] [pool www] pid 31877 script_filename = /var/www/html/informe.php [0x00007f3a1c2130a0] sleep() /var/www/html/informe.php:12 ``` ## Paso 7: Activar la página de estado del pool La página de estado muestra en tiempo real cuántos procesos están activos, si hay peticiones en cola y cuántas veces se ha alcanzado `pm.max_children`. Edita `www.conf` y descomenta la línea `pm.status_path`: ```ini pm.status_path = /status ``` Recarga PHP-FPM: ```bash sudo systemctl reload php8.3-fpm ``` Para consultarla sin exponerla en el servidor web, instala `cgi-fcgi`, que habla FastCGI directamente con el socket: ```bash sudo apt install libfcgi-bin ``` ```bash sudo SCRIPT_NAME=/status SCRIPT_FILENAME=/status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.3-fpm.sock ``` ```output Content-type: text/plain;charset=UTF-8 pool: www process manager: dynamic start time: 25/Sep/2026:11:05:12 +0000 start since: 812 accepted conn: 15230 listen queue: 0 max listen queue: 0 listen queue len: 0 idle processes: 12 active processes: 3 total processes: 15 max active processes: 27 max children reached: 0 slow requests: 0 ``` Los campos que importan: - `listen queue`: peticiones esperando un proceso libre ahora mismo. Debe ser 0 casi siempre. - `max active processes`: el máximo de procesos ocupados a la vez desde el arranque. Si se acerca a `pm.max_children`, estás cerca del límite. - `max children reached`: cuántas veces se ha llegado al límite. Si crece y aún tienes memoria libre, sube `pm.max_children`; si no tienes memoria, necesitas más RAM u optimizar la aplicación. - `slow requests`: peticiones que han superado `request_slowlog_timeout`. ## Paso 8: Separar aplicaciones en pools distintos Si alojas varias aplicaciones, dales un pool propio a cada una. Así una web con un pico de tráfico no deja sin procesos a las demás y cada una se ejecuta con su propio usuario. Crea un pool nuevo para `your_app`: ```bash sudo nano /etc/php/8.3/fpm/pool.d/your_app.conf ``` ```ini [your_app] user = your_user group = your_user listen = /run/php/php8.3-fpm-your_app.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 pm = ondemand pm.max_children = 10 pm.process_idle_timeout = 10s pm.max_requests = 500 pm.status_path = /status request_terminate_timeout = 60s ``` `listen.owner` y `listen.group` son `www-data` para que Nginx o Apache puedan escribir en el socket, mientras el código PHP se ejecuta como `your_user`. Ten en cuenta que la suma de `pm.max_children` de todos los pools es la que debe respetar el cálculo del paso 3. Comprueba y recarga: ```bash sudo php-fpm8.3 -t && sudo systemctl reload php8.3-fpm ls -l /run/php/ ``` ```output srw-rw---- 1 www-data www-data 0 Sep 25 11:30 php8.3-fpm-your_app.sock srw-rw---- 1 www-data www-data 0 Sep 25 11:30 php8.3-fpm.sock ``` Por último, apunta el virtual host de esa aplicación al nuevo socket. En Nginx: ```nginx fastcgi_pass unix:/run/php/php8.3-fpm-your_app.sock; ``` ## Solución de problemas - **`502 Bad Gateway` tras recargar**: el socket no existe o el servidor web no tiene permisos. Comprueba `ls -l /run/php/` y que la ruta en `fastcgi_pass` coincide con `listen`. - **PHP-FPM no arranca**: revisa `sudo journalctl -u php8.3-fpm -n 50`. Con `dynamic`, un error frecuente es que `pm.start_servers` quede fuera del rango entre `pm.min_spare_servers` y `pm.max_spare_servers`. - **El servidor usa swap o aparece el OOM killer**: `pm.max_children` es demasiado alto para la memoria disponible. Vuelve a medir la RAM por proceso y rebaja el valor. - **`504 Gateway Timeout`**: el servidor web se ha cansado de esperar antes que PHP. Revisa el slowlog para encontrar el código lento y alinea `fastcgi_read_timeout` con `request_terminate_timeout`. ## Conclusión Has dimensionado el pool de PHP-FPM a partir de la memoria real de tus procesos, has elegido el gestor de procesos adecuado y tienes la página de estado y el slowlog para confirmar que no hay peticiones en cola ni scripts bloqueados. Como siguientes pasos, activa y ajusta OPcache para reducir el tiempo de CPU de cada petición, añade una caché de datos con Memcached o Redis y mide el resultado con Apache Bench antes y después de cada cambio.