15%

Ahorra 15%<\/span> en todos los servicios de hosting

Pon a prueba tus habilidades y obtén Descuento<\/span> en cualquier plan de hosting

Usa el código:

Skills
Comenzar
10.10.2024

PHP-FPM (FastCGI Process Manager): Guía Completa de Configuración, Ajuste y Optimización

PHP-FPM (PHP FastCGI Process Manager) es un gestor de procesos PHP de alto rendimiento que implementa el protocolo FastCGI para desacoplar la ejecución de PHP del proceso del servidor web. En lugar de generar un nuevo intérprete PHP para cada solicitud HTTP entrante — como hace el CGI tradicional — PHP-FPM mantiene un grupo persistente de procesos trabajadores que aceptan, ejecutan y devuelven respuestas PHP con una sobrecarga significativamente menor.

Para cualquier servidor web en producción que ejecute WordPress, Laravel, Symfony o aplicaciones PHP personalizadas, PHP-FPM es el manejador estándar de la industria. Permite un control detallado sobre el ciclo de vida de los procesos, los límites de memoria, la cola de solicitudes y el aislamiento por aplicación — capacidades que simplemente no están disponibles con mod_php o CGI básico.

Cómo PHP-FPM se diferencia de CGI y mod_php

Para entender por qué PHP-FPM es importante, es útil ver exactamente qué reemplaza y por qué esas alternativas son insuficientes a escala.

CaracterísticaCGImod_phpPHP-FPM
Modelo de procesoNuevo proceso por solicitudIntegrado en ApacheGrupo de trabajadores persistente
Eficiencia de memoriaMuy bajaModeradaExcelente
Acoplamiento al servidor webEstrechoEstrecho (solo Apache)Desacoplado (cualquier servidor)
Aislamiento por sitioNingunoNingunoCompleto (grupos separados)
Recarga sin interrupcionesNoNo
Registro lento / perfiladoNoNo
Escalado dinámico de procesosNoNo
Soporte de socket UnixNoNo
Compatible con NGINXNoNo

CGI genera un nuevo proceso del sistema operativo para cada solicitud. Con tráfico moderado, esto crea miles de ciclos fork/exec/exit por minuto, saturando la CPU y la memoria. mod_php integra el intérprete PHP directamente en cada trabajador de Apache, lo que significa que cada proceso de Apache — incluso uno que sirve una imagen estática — lleva el runtime completo de PHP en memoria. PHP-FPM resuelve ambos problemas: los trabajadores son persistentes y completamente independientes del servidor web, por lo que NGINX o Apache gestionan los archivos estáticos de forma nativa mientras PHP-FPM maneja únicamente la ejecución de PHP.

Arquitectura de PHP-FPM: Flujo de solicitudes en detalle

Comprender la ruta interna de las solicitudes es esencial para el ajuste y la depuración.

  1. Un navegador envía una solicitud HTTP para un recurso .php.
  2. El servidor web (NGINX o Apache) recibe la solicitud y la compara con un bloque de ubicación o una directiva FilesMatch.
  3. El servidor web reenvía la solicitud a PHP-FPM mediante el protocolo FastCGI — ya sea a través de un socket de dominio Unix (/run/php/php8.2-fpm.sock) o un socket TCP (127.0.0.1:9000).
  4. El proceso maestro de PHP-FPM enruta la solicitud a un trabajador disponible del grupo configurado.
  5. El trabajador ejecuta el script PHP, escribe en stdout y devuelve la respuesta al servidor web.
  6. El servidor web entrega el HTML renderizado al cliente.
  7. El proceso trabajador no termina — regresa al grupo inactivo, listo para la siguiente solicitud.

Los sockets Unix son preferibles a TCP para la comunicación local porque evitan completamente la pila TCP/IP, reduciendo la latencia entre un 10–20% en pruebas de rendimiento y eliminando la sobrecarga del enlace de puertos y el enrutamiento de loopback.

Modos de gestión de procesos

PHP-FPM admite tres modos pm (gestor de procesos), y elegir el incorrecto es uno de los errores de configuración más comunes.

pm = static

Siempre se ejecuta un número fijo de trabajadores, independientemente del tráfico. Úselo en servidores dedicados donde desee memoria preasignada y predecible y pueda asumir la sobrecarga inactiva.

pm = static
pm.max_children = 20

pm = dynamic

PHP-FPM inicia un número base de trabajadores y escala hacia arriba o hacia abajo dentro de los límites definidos. Este es el modo más utilizado y el predeterminado correcto para la mayoría de los entornos de Hosting VPS.

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500

pm = ondemand

Los trabajadores se generan solo cuando llega una solicitud y se eliminan tras pm.process_idle_timeout segundos de inactividad. Esto minimiza el consumo de memoria inactiva y es ideal para sitios de bajo tráfico o entornos compartidos donde coexisten docenas de grupos.

pm = ondemand
pm.max_children = 20
pm.process_idle_timeout = 10s

Advertencia crítica: ondemand introduce una latencia de arranque en frío en la primera solicitud después de un período inactivo. Para aplicaciones sensibles a la latencia, dynamic es siempre la mejor opción.

Cálculo correcto de pm.max_children

Aquí es donde la mayoría de los administradores cometen errores costosos. Establecer pm.max_children demasiado alto provoca agotamiento de memoria y eliminaciones por OOM; demasiado bajo provoca colas de solicitudes y errores 502 bajo carga.

La fórmula correcta:

pm.max_children = (Available RAM for PHP) / (Average PHP worker memory usage)

Para encontrar la memoria promedio de un trabajador PHP:

ps --no-headers -o "rss,cmd" -C php-fpm8.2 | awk '{ sum+=$1 } END { printf "Average: %d MBn", sum/NR/1024 }'

En un VPS con 2 GB de RAM donde NGINX, MySQL y el sistema operativo consumen ~600 MB, dispone de aproximadamente 1.400 MB para PHP. Si cada trabajador usa ~70 MB, su pm.max_children seguro es 20. Nunca lo establezca basándose en suposiciones.

Instalación de PHP-FPM

Debian / Ubuntu

sudo apt update
sudo apt install php8.2-fpm
sudo systemctl enable php8.2-fpm
sudo systemctl start php8.2-fpm

CentOS / AlmaLinux / RHEL (con repositorio Remi)

sudo dnf install epel-release
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo dnf module enable php:remi-8.2
sudo dnf install php-fpm
sudo systemctl enable php-fpm
sudo systemctl start php-fpm

Verifique que el servicio esté en ejecución y confirme la ruta del socket:

sudo systemctl status php8.2-fpm
ls -la /run/php/

Configuración de grupos PHP-FPM

La configuración principal de PHP-FPM se encuentra en /etc/php/8.2/fpm/php-fpm.conf, pero las definiciones de grupos individuales pertenecen a /etc/php/8.2/fpm/pool.d/. En sistemas basados en RHEL, los archivos de grupos residen en /etc/php-fpm.d/.

Cada grupo es un entorno de ejecución aislado. Ejecutar múltiples aplicaciones PHP en el mismo servidor — por ejemplo, un sitio WordPress y una API Laravel — implica crear archivos de grupo separados con usuarios, rutas de socket y límites de recursos independientes. Esta es la arquitectura correcta para configuraciones multi-inquilino y es mucho más segura que compartir un único grupo.

Ejemplo: Configuración de grupo en producción

[myapp]
user = myapp
group = myapp

; Unix socket — always prefer this over TCP for local communication
listen = /run/php/myapp-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; Process manager
pm = dynamic
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 1000

; Slow log — log requests taking longer than 2 seconds
slowlog = /var/log/php-fpm/myapp-slow.log
request_slowlog_timeout = 2s

; Status and ping endpoints
pm.status_path = /fpm-status
ping.path = /fpm-ping

; Environment isolation
clear_env = yes
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin

; PHP value overrides per pool
php_admin_value[error_log] = /var/log/php-fpm/myapp-error.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M

La directiva clear_env = yes es una configuración crítica de seguridad que se pasa por alto con frecuencia. Sin ella, los trabajadores PHP heredan todas las variables de entorno del proceso maestro, lo que puede filtrar datos sensibles del sistema en el $_ENV de su aplicación.

Integración de PHP-FPM con NGINX

NGINX no tiene capacidad nativa de ejecución PHP — depende completamente de FastCGI para delegar las solicitudes PHP. Esto es en realidad una ventaja arquitectónica: NGINX gestiona archivos estáticos con un costo casi nulo mientras PHP-FPM maneja únicamente lo que requiere ejecución.

server {
    listen 80;
    server_name example.com;
    root /var/www/myapp/public;
    index index.php index.html;

    # Serve static files directly, no PHP involvement
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Delegate PHP to PHP-FPM
    location ~ .php$ {
        # Security: prevent executing uploaded files as PHP
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;

        fastcgi_pass unix:/run/php/myapp-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;

        # Performance tuning
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_read_timeout 300;
    }

    # Block access to the FPM status page from public
    location ~ ^/(fpm-status|fpm-ping)$ {
        allow 127.0.0.1;
        deny all;
        fastcgi_pass unix:/run/php/myapp-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Nota de seguridad: La línea try_files $uri =404; antes de fastcgi_pass no es opcional. Sin ella, NGINX reenviará solicitudes de archivos inexistentes a PHP-FPM, habilitando ataques de path traversal donde un atacante sube una imagen que contiene código PHP y engaña al servidor para que lo ejecute.

Integración de PHP-FPM con Apache

Apache requiere mod_proxy_fcgi para comunicarse con PHP-FPM. A diferencia de mod_php, este enfoque permite a Apache ejecutar PHP-FPM como un usuario separado, mejorando el aislamiento.

sudo a2enmod proxy_fcgi setenvif
sudo systemctl restart apache2

Configuración del host virtual:

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/myapp/public

    <Directory /var/www/myapp/public>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    <FilesMatch ".php$">
        SetHandler "proxy:unix:/run/php/myapp-fpm.sock|fcgi://localhost/"
    </FilesMatch>

    ErrorLog ${APACHE_LOG_DIR}/myapp-error.log
    CustomLog ${APACHE_LOG_DIR}/myapp-access.log combined
</VirtualHost>

Habilitación y uso de la página de estado de PHP-FPM

La página de estado integrada es una de las herramientas de diagnóstico más infrautilizadas de PHP-FPM. Una vez que pm.status_path está configurado en el archivo del grupo, consúltelo directamente:

sudo -u www-data SCRIPT_NAME=/fpm-status SCRIPT_FILENAME=/fpm-status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/myapp-fpm.sock

O, de forma más práctica, a través de curl después de exponerlo en un endpoint interno restringido:

curl http://127.0.0.1/fpm-status?full

Métricas clave a monitorear:

  • listen queue: Solicitudes en espera de un trabajador libre. Cualquier valor superior a 0 bajo carga sostenida significa que pm.max_children es demasiado bajo.
  • active processes: Trabajadores ejecutando PHP actualmente. Si esto iguala consistentemente pm.max_children, está al límite de capacidad.
  • slow requests: Recuento acumulado de solicitudes que superaron request_slowlog_timeout. Un número creciente indica cuellos de botella a nivel de aplicación.

Uso del registro lento para depuración de rendimiento

El registro lento captura una traza completa de la pila PHP para cualquier solicitud que supere el umbral configurado. Esto es invaluable para identificar problemas de consultas N+1, llamadas de I/O bloqueantes o bucles ineficientes sin necesidad de un perfilador completo.

slowlog = /var/log/php-fpm/myapp-slow.log
request_slowlog_timeout = 2s

Una entrada del registro lento tiene este aspecto:

[21-Jun-2025 14:32:11]  [pool myapp] pid 18432
script_filename = /var/www/myapp/public/index.php
[0x00007f3b4c001e80] PDOStatement->execute() /var/www/myapp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:338
[0x00007f3b4c001d40] runQueryCallback() /var/www/myapp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:295

Esto le indica inmediatamente que el cuello de botella es una consulta de base de datos, no la lógica PHP — dirigiendo su esfuerzo de optimización con precisión.

PHP-FPM con OPcache: La combinación esencial

PHP-FPM por sí solo gestiona los procesos; OPcache elimina el costo de analizar y compilar archivos fuente PHP en cada solicitud. Juntos, forman la pila de rendimiento completa para PHP en Linux.

Habilite y ajuste OPcache en /etc/php/8.2/fpm/php.ini o en un /etc/php/8.2/fpm/conf.d/10-opcache.ini dedicado:

opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.jit_buffer_size=128M
opcache.jit=tracing

Establecer validate_timestamps=0 deshabilita las comprobaciones de modificación de archivos en cada solicitud — una mejora de rendimiento significativa en producción. Cuando implemente nuevo código, active un restablecimiento de caché explícitamente:

sudo systemctl reload php8.2-fpm

En un VPS con cPanel, la configuración de OPcache suele estar disponible en la interfaz de configuración PHP, pero el ajuste manual mediante archivos .ini siempre proporciona un control más preciso.

Refuerzo de seguridad para PHP-FPM

Ejecutar cada grupo como un usuario del sistema dedicado

Nunca ejecute grupos PHP-FPM como root ni como un usuario www-data compartido entre múltiples aplicaciones. Cree un usuario del sistema dedicado por aplicación:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp

Luego establezca user = myapp y group = myapp en la configuración del grupo. Esto garantiza que una aplicación PHP comprometida no pueda leer archivos pertenecientes a otras aplicaciones en el mismo servidor.

Restringir funciones PHP

En el bloque php_admin_value del grupo, deshabilite las funciones que no tienen uso legítimo en aplicaciones web:

php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

Limitar Open Basedir

Restrinja el acceso de archivos de PHP al directorio de la aplicación:

php_admin_value[open_basedir] = /var/www/myapp:/tmp

Usar sockets Unix con permisos estrictos

Los sockets TCP (127.0.0.1:9000) son accesibles para cualquier proceso en el servidor. Los sockets Unix con listen.mode = 0660 restringen el acceso únicamente al usuario y grupo propietarios.

Verificación de la pila completa

Después de configurar PHP-FPM y su servidor web, verifique toda la cadena antes de poner en producción.

Recargue todos los servicios:

sudo systemctl reload php8.2-fpm
sudo systemctl reload nginx
# or
sudo systemctl reload apache2

Pruebe la sintaxis de configuración de NGINX antes de recargar:

sudo nginx -t

Cree un archivo de información temporal (elimínelo después de la verificación — expone datos sensibles del servidor):

echo "<?php phpinfo();" | sudo tee /var/www/myapp/public/phpinfo.php

Abra http://example.com/phpinfo.php en un navegador y confirme:

  • Server API muestra FPM/FastCGI
  • PHP Version coincide con la versión instalada
  • La sección OPcache está presente y habilitada

Luego elimine el archivo inmediatamente:

sudo rm /var/www/myapp/public/phpinfo.php

PHP-FPM en entornos multi-aplicación y de alto tráfico

En un Servidor Dedicado que aloja docenas de aplicaciones PHP, la arquitectura multi-grupo se vuelve esencial. Cada aplicación obtiene su propio grupo con pm.max_children, límites de memoria y rutas de registro lento ajustados de forma independiente. Una aplicación con mal comportamiento que agota su grupo de trabajadores no afecta a otras aplicaciones.

Para escenarios de alto tráfico, combine PHP-FPM con:

  • Caché FastCGI de NGINX (fastcgi_cache) para servir respuestas PHP en caché como archivos estáticos, evitando completamente PHP-FPM para solicitudes repetidas
  • Redis o Memcached para el almacenamiento de sesiones PHP, reemplazando las sesiones predeterminadas basadas en archivos que crean contención de I/O bajo carga
  • Escalado horizontal ejecutando PHP-FPM en servidores de aplicaciones detrás de un balanceador de carga, con NGINX en un nodo frontal separado

Si su pila incluye terminación SSL, combinar PHP-FPM con Certificados SSL correctamente configurados en la capa NGINX garantiza que los handshakes TLS se gestionen antes de que las solicitudes lleguen a PHP-FPM, manteniendo los trabajadores PHP enfocados exclusivamente en la lógica de la aplicación.

Para cargas de trabajo PHP con uso intensivo de cómputo — inferencia de aprendizaje automático mediante enlaces PHP, procesamiento de imágenes o transcodificación de vídeo — considere el Hosting GPU donde PHP-FPM puede delegar el cómputo pesado a bibliotecas aceleradas por GPU mientras mantiene el manejo estándar de solicitudes para la capa web.

Matriz de decisión clave y lista de verificación técnica

Antes de implementar PHP-FPM en producción, verifique cada elemento de esta lista:

Selección del gestor de procesos

  • Use pm = dynamic para cargas de trabajo VPS de propósito general
  • Use pm = static solo en servidores dedicados con tráfico sostenido y predecible
  • Use pm = ondemand solo para grupos de bajo tráfico o desarrollo

Planificación de capacidad

  • Mida la memoria real del trabajador con ps antes de establecer pm.max_children
  • Reserve al menos el 20% de la RAM total para el sistema operativo, el servidor web y la base de datos
  • Establezca pm.max_requests entre 500–1000 para prevenir la acumulación de fugas de memoria

Seguridad

  • Cada grupo de aplicaciones se ejecuta con su propio usuario del sistema
  • clear_env = yes está establecido en cada grupo
  • open_basedir restringe el acceso a archivos al directorio de la aplicación
  • disable_functions bloquea las funciones de ejecución de shell
  • Se usan sockets Unix en lugar de sockets TCP

Observabilidad

  • pm.status_path está configurado y accesible solo desde localhost
  • slowlog está habilitado con un request_slowlog_timeout de 2–5 segundos
  • La rotación de registros está configurada para todos los archivos de registro de PHP-FPM

Rendimiento

  • OPcache está habilitado con validate_timestamps=0 en producción
  • El caché FastCGI de NGINX está configurado para endpoints cacheables
  • El manejador de sesiones PHP está configurado en Redis o Memcached, no en archivos

Operacional

  • sudo systemctl reload php8.2-fpm se usa para cambios de configuración sin tiempo de inactividad (no restart)
  • phpinfo.php se elimina del directorio raíz del documento inmediatamente después de la verificación
  • La configuración del grupo está bajo control de versiones junto con el código de la aplicación

Preguntas frecuentes

¿Cuál es la diferencia entre PHP-FPM y mod_php?

mod_php integra el intérprete PHP dentro de cada proceso trabajador de Apache, consumiendo memoria incluso al servir archivos estáticos y acoplando estrechamente PHP a Apache. PHP-FPM se ejecuta como un servicio completamente separado, se comunica mediante FastCGI, funciona con cualquier servidor web incluido NGINX, y permite el aislamiento de procesos por aplicación con límites de recursos independientes.

¿Cómo elijo entre un socket Unix y un socket TCP para PHP-FPM?

Use un socket Unix (listen = /run/php/app-fpm.sock) siempre que PHP-FPM y el servidor web se ejecuten en la misma máquina física o virtual. Los sockets Unix evitan la pila TCP/IP, reduciendo la latencia y eliminando conflictos de puertos. Use un socket TCP (listen = 127.0.0.1:9000) solo cuando PHP-FPM se ejecute en un host diferente al del servidor web.

¿Por qué obtengo errores 502 Bad Gateway bajo carga?

Un error 502 de NGINX apuntando a PHP-FPM casi siempre significa que la cola de escucha está llena — todos los trabajadores están ocupados y se están rechazando nuevas conexiones. Compruebe pm.status_path para un valor listen queue distinto de cero. La solución es aumentar pm.max_children (si la RAM lo permite) u optimizar los scripts PHP lentos identificados mediante el registro lento.

¿Cómo recargo PHP-FPM sin interrumpir las conexiones activas?

Use sudo systemctl reload php8.2-fpm en lugar de restart. La señal reload (SIGUSR2) hace que el proceso maestro reinicie los trabajadores de forma gradual: las solicitudes existentes se completan normalmente mientras los nuevos trabajadores adoptan la configuración actualizada. Un restart forzado termina todos los trabajadores inmediatamente, descartando las solicitudes en curso.

¿Puede PHP-FPM ejecutar múltiples versiones de PHP simultáneamente en un servidor?

Sí. Instale múltiples versiones de PHP (p. ej., php7.4-fpm y php8.2-fpm) y configure cada grupo de aplicaciones para usar la ruta de socket apropiada. En NGINX, apunte fastcgi_pass al socket correcto por bloque de servidor. Este es un patrón estándar en infraestructura compartida gestionada mediante Paneles de Control VPS y es totalmente compatible en Hosting VPS con acceso root.

15%

Ahorra 15%<\/span> en todos los servicios de hosting

Pon a prueba tus habilidades y obtén Descuento<\/span> en cualquier plan de hosting

Usa el código:

Skills
Comenzar