--- title: "Cómo instalar y configurar PHP-FPM con Nginx en Ubuntu 24.04" description: "Instala PHP-FPM 8.3 en Ubuntu 24.04, crea un pool por sitio, conéctalo a Nginx, ajusta pm.max_children según tu RAM y activa la página de estado y el slowlog." category: "Despliegue de Aplicaciones" language: es source: https://cubepath.com/es/docs/despliegue-de-aplicaciones/instalacion-y-configuracion-de-php-fpm updated: 2026-09-25 --- # Cómo instalar y configurar PHP-FPM con Nginx en Ubuntu 24.04 PHP-FPM (FastCGI Process Manager) es el gestor de procesos que ejecuta PHP detrás de servidores web como Nginx. Mantiene un conjunto de procesos (un *pool*) listos para atender peticiones y permite aislar cada sitio con su propio usuario, socket y límites. En este tutorial instalarás PHP-FPM 8.3 en Ubuntu 24.04, crearás un pool dedicado para un sitio, lo conectarás a Nginx y ajustarás el número de procesos según la memoria del servidor. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 1 GB de RAM. - Un usuario no root con privilegios `sudo`. - Nginx instalado (`sudo apt install nginx`) y el puerto 80 abierto en el cortafuegos (`sudo ufw allow 'Nginx HTTP'`). - Un dominio o subdominio apuntando a la IP del servidor si quieres probar con un nombre real. En los ejemplos se usa `your_domain`; sustitúyelo por el tuyo. ## Paso 1: Instalar PHP-FPM Ubuntu 24.04 incluye PHP 8.3 en sus repositorios oficiales. Instala PHP-FPM junto con las extensiones que usan la mayoría de aplicaciones (MySQL, cURL, XML, mbstring, zip, intl y GD): ```bash sudo apt update sudo apt install php8.3-fpm php8.3-cli php8.3-opcache php8.3-mysql php8.3-curl php8.3-xml php8.3-mbstring php8.3-zip php8.3-intl php8.3-gd ``` El paquete crea y arranca el servicio `php8.3-fpm`. Comprueba que está activo: ```bash systemctl status php8.3-fpm ``` ```output ● php8.3-fpm.service - The PHP 8.3 FastCGI Process Manager Loaded: loaded (/usr/lib/systemd/system/php8.3-fpm.service; enabled; preset: enabled) Active: active (running) since ... ``` Verifica también la versión del binario FPM: ```bash php-fpm8.3 -v ``` ```output PHP 8.3.6 (fpm-fcgi) (built: ...) ``` > Nota: Instalar el paquete `php8.3-fpm` en lugar de `php` evita que apt instale Apache y `libapache2-mod-php` como dependencia. ## Paso 2: Conocer los archivos de configuración PHP-FPM reparte su configuración en varios archivos. Estos son los que vas a tocar: | Ruta | Para qué sirve | |------|----------------| | `/etc/php/8.3/fpm/php-fpm.conf` | Configuración global del gestor (logs, reinicio de emergencia) | | `/etc/php/8.3/fpm/pool.d/*.conf` | Un archivo por pool; `www.conf` es el pool por defecto | | `/etc/php/8.3/fpm/php.ini` | Opciones de PHP para FPM (distinto del `php.ini` de la CLI) | | `/run/php/php8.3-fpm.sock` | Socket Unix del pool `www` | | `/var/log/php8.3-fpm.log` | Log del gestor de procesos | Antes de reiniciar el servicio tras cualquier cambio, valida la sintaxis: ```bash sudo php-fpm8.3 -t ``` ```output [25-Sep-2026 10:00:00] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful ``` ## Paso 3: Ajustar php.ini para FPM Abre el `php.ini` que usa FPM: ```bash sudo nano /etc/php/8.3/fpm/php.ini ``` Busca y ajusta estas directivas. Los valores son un punto de partida razonable para una aplicación web típica: ```ini memory_limit = 256M upload_max_filesize = 32M post_max_size = 32M max_execution_time = 60 expose_php = Off date.timezone = Europe/Madrid opcache.enable = 1 opcache.memory_consumption = 128 opcache.interned_strings_buffer = 16 opcache.max_accelerated_files = 10000 opcache.validate_timestamps = 1 ``` `post_max_size` debe ser igual o mayor que `upload_max_filesize`. OPcache guarda el código PHP compilado en memoria y es la mejora de rendimiento más barata que puedes aplicar. Si despliegas código siempre reiniciando PHP-FPM, puedes poner `opcache.validate_timestamps = 0` para ahorrar comprobaciones de disco. Aplica los cambios: ```bash sudo php-fpm8.3 -t && sudo systemctl reload php8.3-fpm ``` ## Paso 4: Crear un pool dedicado para tu sitio El pool `www` ejecuta todo como `www-data`. Si alojas varios sitios, dale a cada uno su propio usuario y pool: si un sitio queda comprometido, no puede leer los archivos de los demás. Crea un usuario de sistema sin shell para el sitio y su directorio web: ```bash sudo useradd --system --no-create-home --shell /usr/sbin/nologin your_site sudo mkdir -p /var/www/your_domain/public sudo chown -R your_site:your_site /var/www/your_domain ``` Crea el archivo del pool: ```bash sudo nano /etc/php/8.3/fpm/pool.d/your_site.conf ``` Añade este contenido: ```ini [your_site] user = your_site group = your_site listen = /run/php/php8.3-fpm-your_site.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 pm = dynamic pm.max_children = 10 pm.start_servers = 3 pm.min_spare_servers = 2 pm.max_spare_servers = 5 pm.max_requests = 500 pm.status_path = /fpm-status ping.path = /fpm-ping slowlog = /var/log/php8.3-fpm-your_site-slow.log request_slowlog_timeout = 5s request_terminate_timeout = 120s php_admin_value[error_log] = /var/log/php8.3-fpm-your_site-error.log php_admin_flag[log_errors] = on ``` Qué hace cada bloque: - `user`/`group`: los procesos PHP se ejecutan con este usuario. - `listen.*`: el socket pertenece a `www-data` para que Nginx pueda conectarse a él. - `pm.*`: controla cuántos procesos hay (se ajusta en el paso 6). `pm.max_requests` recicla cada proceso tras 500 peticiones para contener fugas de memoria. - `pm.status_path` y `ping.path`: activan la página de estado y el endpoint de salud. - `slowlog`: registra la traza de cualquier petición que tarde más de 5 segundos. - `php_admin_value`: fija valores que el código de la aplicación no puede sobrescribir con `ini_set()`. Valida y recarga: ```bash sudo php-fpm8.3 -t && sudo systemctl reload php8.3-fpm ``` Comprueba que el nuevo socket existe: ```bash ls -l /run/php/*.sock ``` ```output srw-rw---- 1 www-data www-data 0 Sep 25 10:05 php8.3-fpm-your_site.sock srw-rw---- 1 www-data www-data 0 Sep 25 10:05 php8.3-fpm.sock ``` ## Paso 5: Conectar Nginx al pool Crea el bloque de servidor del sitio: ```bash sudo nano /etc/nginx/sites-available/your_domain ``` ```nginx server { listen 80; listen [::]:80; server_name your_domain; root /var/www/your_domain/public; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.3-fpm-your_site.sock; } location ~ ^/(fpm-status|fpm-ping)$ { allow 127.0.0.1; deny all; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $fastcgi_script_name; fastcgi_pass unix:/run/php/php8.3-fpm-your_site.sock; } location ~ /\.(?!well-known) { deny all; } } ``` El snippet `snippets/fastcgi-php.conf` que trae Ubuntu ya define `SCRIPT_FILENAME` y devuelve 404 si el archivo `.php` no existe, lo que evita que se ejecuten rutas arbitrarias como PHP. La página de estado solo responde a peticiones desde el propio servidor. Activa el sitio, valida la configuración y recarga Nginx: ```bash sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` Crea un script de prueba que muestre con qué usuario se ejecuta PHP: ```bash echo ' /dev/null ``` ```bash curl -H "Host: your_domain" http://127.0.0.1/test.php ``` ```output PHP 8.3.6 como your_site ``` Si ves el nombre del usuario del pool, Nginx está usando el socket correcto. Borra el archivo de prueba: ```bash sudo rm /var/www/your_domain/public/test.php ``` ## Paso 6: Calcular pm.max_children `pm.max_children` es el número máximo de procesos PHP simultáneos del pool. Si es demasiado bajo, las peticiones hacen cola; si es demasiado alto, el servidor se queda sin RAM y empieza a usar swap o el OOM killer mata procesos. La fórmula es: ```text pm.max_children = (RAM disponible para PHP) / (memoria media por proceso) ``` Con la aplicación recibiendo tráfico real, mide la memoria media (RSS) de los procesos hijos de PHP-FPM en MB: ```bash ps --no-headers -o rss -C php-fpm8.3 | awk '{sum+=$1; n++} END {printf "%d procesos, media %.0f MB\n", n, sum/n/1024}' ``` ```output 6 procesos, media 48 MB ``` Mira la memoria total y la que ya consumen otros servicios (base de datos, Nginx, caché): ```bash free -m ``` Ejemplo: un servidor de 4 GB donde MySQL y el sistema usan unos 1.500 MB deja unos 2.500 MB para PHP. Con procesos de 48 MB, `2500 / 48 ≈ 52`. Redondea hacia abajo y deja margen: `pm.max_children = 45`. Elige además el modo del gestor: | Modo | Cuándo usarlo | |------|---------------| | `dynamic` | Opción general. Mantiene entre `min_spare` y `max_spare` procesos ociosos. | | `ondemand` | Muchos sitios con poco tráfico. Crea procesos al recibir peticiones y los cierra tras `pm.process_idle_timeout`. | | `static` | Servidor dedicado a una sola aplicación con tráfico alto y constante. Siempre hay `max_children` procesos. | Para `dynamic`, una regla habitual es `pm.start_servers` entre `min_spare_servers` y `max_spare_servers`, con `max_spare_servers` alrededor del 25 % de `max_children`. Por ejemplo, para 45 procesos: ```ini pm = dynamic pm.max_children = 45 pm.start_servers = 8 pm.min_spare_servers = 5 pm.max_spare_servers = 12 ``` Aplica los valores en `/etc/php/8.3/fpm/pool.d/your_site.conf` y recarga: ```bash sudo php-fpm8.3 -t && sudo systemctl reload php8.3-fpm ``` ## Paso 7: Consultar la página de estado y el slowlog La página de estado indica si el pool se está quedando corto. Consúltala desde el propio servidor: ```bash curl -s -H "Host: your_domain" http://127.0.0.1/fpm-status ``` ```output pool: your_site process manager: dynamic start time: 25/Sep/2026:10:05:12 +0000 accepted conn: 1824 listen queue: 0 max listen queue: 0 idle processes: 4 active processes: 1 total processes: 5 max active processes: 9 max children reached: 0 slow requests: 2 ``` Los dos campos importantes son: - `max children reached`: si es mayor que 0, el pool llegó al límite y hubo peticiones esperando. Sube `pm.max_children` si tienes RAM libre. - `listen queue`: peticiones esperando en este momento. Debería ser 0 casi siempre. Añade `?full` para ver cada proceso o `?json` para integrarlo en un sistema de monitorización. El endpoint de salud devuelve `pong` si el pool responde: ```bash curl -s -H "Host: your_domain" http://127.0.0.1/fpm-ping ``` ```output pong ``` Cuando `slow requests` crece, el slowlog muestra en qué función estaba cada petición lenta: ```bash sudo tail -n 30 /var/log/php8.3-fpm-your_site-slow.log ``` ```output [25-Sep-2026 10:32:41] [pool your_site] pid 21457 script_filename = /var/www/your_domain/public/index.php [0x00007f...] curl_exec() /var/www/your_domain/public/lib/Api.php:88 [0x00007f...] fetchRates() /var/www/your_domain/public/index.php:14 ``` En este ejemplo la lentitud viene de una llamada HTTP externa en `Api.php`, no de PHP-FPM. ## Solución de problemas **502 Bad Gateway en Nginx.** Nginx no puede hablar con el socket. Revisa que PHP-FPM está activo y que la ruta de `fastcgi_pass` coincide con `listen` del pool: ```bash sudo tail -n 20 /var/log/nginx/error.log ``` Un error `connect() to unix:/run/php/... failed (2: No such file or directory)` indica una ruta incorrecta o un pool que no arrancó. `(13: Permission denied)` indica que `listen.owner`/`listen.group` no son `www-data`. **PHP-FPM no arranca tras un cambio.** Ejecuta `sudo php-fpm8.3 -t` para ver la línea con el error y consulta el journal: ```bash sudo journalctl -u php8.3-fpm -n 50 --no-pager ``` **Aviso "server reached pm.max_children setting".** Aparece en `/var/log/php8.3-fpm.log`. Repite el cálculo del paso 6 y sube el valor, o busca en el slowlog qué hace que las peticiones tarden tanto. **Archivos subidos que fallan con 413.** Nginx limita el cuerpo de la petición a 1 MB por defecto. Añade `client_max_body_size 32M;` al bloque `server` para que coincida con `upload_max_filesize`. ## Conclusión Tienes PHP-FPM 8.3 funcionando en Ubuntu 24.04 con un pool aislado por sitio, conectado a Nginx por socket Unix, con OPcache activo y un número de procesos calculado según la RAM real. La página de estado y el slowlog te dicen cuándo ajustar esos valores. Como siguientes pasos puedes proteger el sitio con un certificado TLS de Let's Encrypt usando Certbot, instalar otra versión de PHP en paralelo para aplicaciones antiguas, o desplegar una aplicación como WordPress sobre este pool.