title: "Instalación y Configuración de PHP-FPM: Guía Completa para Rendimiento Óptimo" description: "Guía exhaustiva para instalar y configurar PHP-FPM (FastCGI Process Manager) con Nginx o Apache. Incluye optimización de rendimiento, gestión de pools, configuración de seguridad y mejores prácticas para entornos de producción." date: 2024-03-15 tags: ["PHP-FPM", "PHP", "Nginx", "Apache", "FastCGI", "Performance Optimization", "Web Server", "Process Management"] categories: ["Application Deployment", "Web Servers"]
Instalación y Configuración de PHP-FPM: Guía Completa para Rendimiento Óptimo
PHP-FPM (FastCGI Process Manager) es una implementación alternativa de PHP FastCGI con funcionalidades adicionales especialmente útiles para sitios web de alto tráfico. Esta guía cubre la instalación, configuración y optimización de PHP-FPM.
Tabla de Contenidos
- ¿Qué es PHP-FPM?
- Requisitos Previos
- Instalación de PHP-FPM
- Configuración Básica
- Gestión de Pools
- Integración con Nginx
- Integración con Apache
- Optimización del Rendimiento
- Configuración de Seguridad
- Monitoreo y Depuración
- Solución de Problemas
¿Qué es PHP-FPM?
PHP-FPM (FastCGI Process Manager) es un gestor de procesos PHP alternativo que incluye:
- Gestión avanzada de procesos: con stop/start suave
- Pools de workers: capacidad para iniciar workers con diferentes uid/gid/chroot/environment
- Logging adaptativo: para stdout y stderr
- Reinicios de emergencia: en caso de destrucción accidental de caché opcode
- Soporte de carga acelerada: con mecanismos especiales de cache opcode
- Terminación lenta: con configuración de tiempo de espera ajustable
- Página de estado: similar a mod_status de Apache
Ventajas sobre mod_php
- Mejor rendimiento y uso de memoria
- No requiere ejecutar el servidor web como usuario de PHP
- Pools separados para diferentes sitios web
- Estadísticas y estado incorporados
- Mejor aislamiento y seguridad
- Escalado más fácil
Requisitos Previos
Antes de comenzar, asegúrate de tener:
- Un servidor con Ubuntu 20.04/22.04 o Debian 10/11
- Acceso root o privilegios sudo
- Nginx o Apache instalado
- Conocimientos básicos de administración de servidores Linux
Instalación de PHP-FPM
En Ubuntu/Debian
# Update package repository
sudo apt update
# Install PHP-FPM and common extensions
sudo apt install php-fpm php-cli php-mysql php-curl php-gd php-mbstring php-xml php-xmlrpc php-zip php-opcache -y
# Check PHP-FPM version
php-fpm8.1 -v # Replace 8.1 with your PHP version
# Check PHP-FPM status
sudo systemctl status php8.1-fpm
Instalar Versión Específica de PHP
Para instalar una versión específica de PHP:
# Add PHP repository
sudo apt install software-properties-common -y
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
# Install specific PHP version (example: PHP 8.2)
sudo apt install php8.2-fpm php8.2-cli php8.2-mysql php8.2-curl php8.2-gd php8.2-mbstring php8.2-xml php8.2-zip php8.2-opcache -y
En CentOS/RHEL
# Install EPEL and Remi repository
sudo yum install epel-release -y
sudo yum install https://rpms.remirepo.net/enterprise/remi-release-8.rpm -y
# Enable PHP 8.1 module
sudo dnf module enable php:remi-8.1 -y
# Install PHP-FPM
sudo yum install php-fpm php-cli php-mysqlnd php-curl php-gd php-mbstring php-xml php-zip php-opcache -y
# Start and enable PHP-FPM
sudo systemctl start php-fpm
sudo systemctl enable php-fpm
Configuración Básica
Estructura de Directorios de PHP-FPM
Ubicaciones importantes:
# Main configuration file
/etc/php/8.1/fpm/php-fpm.conf
# Pool configurations
/etc/php/8.1/fpm/pool.d/
# PHP configuration for FPM
/etc/php/8.1/fpm/php.ini
# Socket location
/var/run/php/php8.1-fpm.sock
# Log files
/var/log/php8.1-fpm.log
Archivo de Configuración Principal (php-fpm.conf)
# Edit main PHP-FPM configuration
sudo nano /etc/php/8.1/fpm/php-fpm.conf
Configuraciones importantes:
;;;;;;;;;;;;;;;;;;;;;
; Global Options ;
;;;;;;;;;;;;;;;;;;;;;
; Pid file
pid = /run/php/php8.1-fpm.pid
; Error log file
error_log = /var/log/php8.1-fpm.log
; Log level
; Possible Values: alert, error, warning, notice, debug
log_level = notice
; Emergency restart threshold
emergency_restart_threshold = 10
emergency_restart_interval = 1m
; Process control timeout
process_control_timeout = 10s
; Maximum number of processes FPM can fork
process.max = 128
; Include pool configurations
include=/etc/php/8.1/fpm/pool.d/*.conf
Configuración de PHP (php.ini)
# Edit PHP configuration for FPM
sudo nano /etc/php/8.1/fpm/php.ini
Configuraciones recomendadas:
;;;;;;;;;;;;;;;;
; Performance ;
;;;;;;;;;;;;;;;;
memory_limit = 256M
max_execution_time = 300
max_input_time = 300
upload_max_filesize = 64M
post_max_size = 64M
max_input_vars = 3000
;;;;;;;;;;;;;;;;
; Error Handling
;;;;;;;;;;;;;;;;
display_errors = Off
log_errors = On
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
error_log = /var/log/php_errors.log
;;;;;;;;;;;;;;;;
; Date/Time ;
;;;;;;;;;;;;;;;;
date.timezone = America/New_York ; Set your timezone
;;;;;;;;;;;;;;;;
; Security ;
;;;;;;;;;;;;;;;;
expose_php = Off
allow_url_fopen = On
allow_url_include = Off
;;;;;;;;;;;;;;;;
; Session ;
;;;;;;;;;;;;;;;;
session.save_handler = files
session.save_path = "/var/lib/php/sessions"
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1
;;;;;;;;;;;;;;;;
; OPcache ;
;;;;;;;;;;;;;;;;
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 2
opcache.fast_shutdown = 1
Gestión de Pools
Los pools permiten ejecutar diferentes sitios web con diferentes configuraciones y usuarios.
Configuración del Pool por Defecto
# Edit default pool configuration
sudo nano /etc/php/8.1/fpm/pool.d/www.conf
Configuración completa del pool:
;;;;;;;;;;;;;;;;;;;;;;;;;
; Pool www ;
;;;;;;;;;;;;;;;;;;;;;;;;;
; Pool name
[www]
; Unix user/group of processes
user = www-data
group = www-data
; Socket or TCP/IP address
listen = /run/php/php8.1-fpm.sock
; Set permissions for unix socket
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Process manager settings
pm = dynamic
; Maximum number of child processes
pm.max_children = 50
; Number of child processes created on startup
pm.start_servers = 5
; Desired minimum number of idle server processes
pm.min_spare_servers = 5
; Desired maximum number of idle server processes
pm.max_spare_servers = 35
; Number of requests each child process should execute
pm.max_requests = 500
; URI to view FPM status page
pm.status_path = /status
; URI to view FPM ping page
ping.path = /ping
; Timeout for serving a single request
request_terminate_timeout = 300
; Slow log
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 5s
; Environment variables
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
; PHP configuration values
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/sessions
Crear un Pool Personalizado
Crea un pool separado para un sitio web específico:
# Create new pool configuration
sudo nano /etc/php/8.1/fpm/pool.d/example.conf
Configuración del pool:
; Pool for example.com
[example]
; Unix user/group
user = example
group = example
; Socket path
listen = /run/php/php8.1-fpm-example.sock
; Socket permissions
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Process manager
pm = dynamic
pm.max_children = 20
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 200
; Chroot environment
; chroot = /var/www/example.com
; Change directory
; chdir = /
; Status and ping
pm.status_path = /status
ping.path = /ping
; Slow log
slowlog = /var/log/php-fpm/example-slow.log
request_slowlog_timeout = 10s
; Timeout
request_terminate_timeout = 120
; Environment variables
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
; PHP values
php_admin_value[error_log] = /var/log/php-fpm/example-error.log
php_admin_flag[log_errors] = on
php_value[memory_limit] = 128M
Crear usuario y directorio:
# Create user
sudo useradd -r -s /bin/false example
# Create necessary directories
sudo mkdir -p /var/www/example.com
sudo mkdir -p /var/log/php-fpm
sudo mkdir -p /var/lib/php/sessions
# Set ownership
sudo chown -R example:example /var/www/example.com
# Restart PHP-FPM
sudo systemctl restart php8.1-fpm
Gestionar Múltiples Pools
# List all pools
sudo ls -la /etc/php/8.1/fpm/pool.d/
# Test configuration
sudo php-fpm8.1 -t
# Restart specific pool (requires systemd service per pool)
sudo systemctl restart php8.1-fpm
# Check pool status via socket
sudo SCRIPT_NAME=/status SCRIPT_FILENAME=/status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.1-fpm.sock
Integración con Nginx
Configuración Básica de Nginx
# Edit Nginx server block
sudo nano /etc/nginx/sites-available/example.com
Configuración completa:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
index index.php index.html index.htm;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM configuration
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# Use Unix socket
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
# Or use TCP socket
# fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Timeouts
fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
}
# Deny access to hidden files
location ~ /\. {
deny all;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
}
Configuración con Pool Personalizado
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
index index.php index.html;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# Use custom pool socket
fastcgi_pass unix:/run/php/php8.1-fpm-example.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Habilitar Página de Estado de PHP-FPM
server {
listen 127.0.0.1:80;
server_name localhost;
location ~ ^/(status|ping)$ {
access_log off;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Probar y recargar Nginx:
# Test Nginx configuration
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginx
Integración con Apache
Instalar mod_proxy_fcgi
# Enable required Apache modules
sudo a2enmod proxy_fcgi setenvif
sudo systemctl restart apache2
Configuración de VirtualHost
# Edit Apache VirtualHost
sudo nano /etc/apache2/sites-available/example.com.conf
Configuración:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
<Directory /var/www/example.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# PHP-FPM configuration
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost"
</FilesMatch>
# Or use TCP socket
# <FilesMatch \.php$>
# SetHandler "proxy:fcgi://127.0.0.1:9000"
# </FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
Habilitar sitio:
# Enable site
sudo a2ensite example.com.conf
# Test Apache configuration
sudo apache2ctl configtest
# Restart Apache
sudo systemctl restart apache2
Optimización del Rendimiento
Calcular Configuración Óptima del Pool
Calcula pm.max_children basado en RAM disponible:
# Check available RAM (in MB)
free -m
# Check average PHP-FPM process memory
ps aux | grep php-fpm | awk '{sum+=$6} END {print sum/NR/1024 " MB"}'
# Formula: pm.max_children = (Total RAM - RAM for other services) / Average process size
# Example: (4096MB - 1024MB) / 50MB = 61
Configuración para Diferentes Escenarios
Servidor Pequeño (1-2GB RAM):
pm = dynamic
pm.max_children = 20
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 200
Servidor Mediano (4-8GB RAM):
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
Servidor Grande (16GB+ RAM):
pm = dynamic
pm.max_children = 100
pm.start_servers = 10
pm.min_spare_servers = 10
pm.max_spare_servers = 20
pm.max_requests = 1000
Tráfico Alto y Predecible:
pm = static
pm.max_children = 50
pm.max_requests = 1000
Optimizar OPcache
# Edit PHP configuration
sudo nano /etc/php/8.1/fpm/conf.d/10-opcache.ini
Configuración optimizada:
; Enable OPcache
opcache.enable = 1
opcache.enable_cli = 0
; Memory settings
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
; Validation
opcache.revalidate_freq = 2
opcache.validate_timestamps = 1
; Performance
opcache.fast_shutdown = 1
opcache.save_comments = 1
; File cache (optional)
; opcache.file_cache = /tmp/opcache
Usar TCP Socket vs Unix Socket
Unix Socket (Mejor para servidor único):
; In pool configuration
listen = /run/php/php8.1-fpm.sock
# In Nginx
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
TCP Socket (Mejor para arquitectura distribuida):
; In pool configuration
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
# In Nginx
fastcgi_pass 127.0.0.1:9000;
Configuración de Seguridad
Limitar Extensiones de Archivo
; Only allow .php files to be executed
security.limit_extensions = .php
Deshabilitar Funciones Peligrosas
; In php.ini
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
Configurar Chroot
; In pool configuration
chroot = /var/www/example.com
chdir = /
Configurar Variables de Entorno de Forma Segura
; Clear all environment variables
clear_env = yes
; Set only required variables
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
Restringir Acceso a Archivos
# Set correct ownership
sudo chown -R www-data:www-data /var/www/example.com
# Set directory permissions
sudo find /var/www/example.com -type d -exec chmod 755 {} \;
# Set file permissions
sudo find /var/www/example.com -type f -exec chmod 644 {} \;
# Protect sensitive files
sudo chmod 600 /var/www/example.com/.env
Monitoreo y Depuración
Habilitar Página de Estado
Accede a la página de estado:
# Via command line
sudo SCRIPT_NAME=/status SCRIPT_FILENAME=/status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.1-fpm.sock
# Via browser (configure Nginx first)
# http://localhost/status
# http://localhost/status?full
# http://localhost/status?json
Salida de ejemplo:
pool: www
process manager: dynamic
start time: 15/Mar/2024:10:30:45 +0000
start since: 3600
accepted conn: 12500
listen queue: 0
max listen queue: 5
listen queue len: 128
idle processes: 5
active processes: 10
total processes: 15
max active processes: 15
max children reached: 0
slow requests: 2
Analizar Logs Lentos
# View slow log
sudo tail -f /var/log/php-fpm/www-slow.log
# Find slowest scripts
sudo cat /var/log/php-fpm/www-slow.log | grep "script_filename" | sort | uniq -c | sort -rn | head -10
Monitorear con Herramientas del Sistema
# Monitor PHP-FPM processes
watch -n 1 'ps aux | grep php-fpm'
# Check process count
ps aux | grep php-fpm | wc -l
# Monitor memory usage
ps aux | grep php-fpm | awk '{sum+=$6} END {print sum/1024 " MB"}'
# Use htop for interactive monitoring
sudo htop -p $(pgrep -d',' php-fpm)
Script de Monitoreo
Crea un script de monitoreo:
# Create monitoring script
sudo nano /usr/local/bin/php-fpm-monitor.sh
Contenido del script:
#!/bin/bash
# PHP-FPM Monitoring Script
echo "=== PHP-FPM Status ==="
date
# Process count
PROCESS_COUNT=$(ps aux | grep php-fpm | grep -v grep | wc -l)
echo "Active processes: $PROCESS_COUNT"
# Memory usage
MEMORY_USAGE=$(ps aux | grep php-fpm | grep -v grep | awk '{sum+=$6} END {print sum/1024}')
echo "Total memory usage: ${MEMORY_USAGE} MB"
# Average memory per process
AVG_MEMORY=$(echo "scale=2; $MEMORY_USAGE / $PROCESS_COUNT" | bc)
echo "Average memory per process: ${AVG_MEMORY} MB"
# CPU usage
CPU_USAGE=$(ps aux | grep php-fpm | grep -v grep | awk '{sum+=$3} END {print sum}')
echo "Total CPU usage: ${CPU_USAGE}%"
# Check status page
echo -e "\n=== Pool Status ==="
sudo SCRIPT_NAME=/status SCRIPT_FILENAME=/status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.1-fpm.sock
# Recent errors
echo -e "\n=== Recent Errors ==="
sudo tail -n 10 /var/log/php8.1-fpm.log
Haz el script ejecutable:
sudo chmod +x /usr/local/bin/php-fpm-monitor.sh
# Run monitoring script
sudo /usr/local/bin/php-fpm-monitor.sh
Solución de Problemas
Errores Comunes y Soluciones
Error: "File not found" (404)
# Check socket permissions
ls -la /run/php/php8.1-fpm.sock
# Verify Nginx user can access socket
sudo -u www-data test -r /run/php/php8.1-fpm.sock && echo "OK" || echo "FAIL"
# Check fastcgi_param in Nginx
grep SCRIPT_FILENAME /etc/nginx/sites-available/example.com
Error: "502 Bad Gateway"
# Check if PHP-FPM is running
sudo systemctl status php8.1-fpm
# Check socket exists
ls -la /run/php/php8.1-fpm.sock
# Restart PHP-FPM
sudo systemctl restart php8.1-fpm
# Check error log
sudo tail -f /var/log/php8.1-fpm.log
Error: "504 Gateway Timeout"
Incrementa los valores de timeout:
; In pool configuration
request_terminate_timeout = 300
# In Nginx
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
Error: Pool llega a max_children
# Check current pool status
sudo SCRIPT_NAME=/status SCRIPT_FILENAME=/status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.1-fpm.sock | grep "max children reached"
# If value > 0, increase pm.max_children
sudo nano /etc/php/8.1/fpm/pool.d/www.conf
# Increase pm.max_children value
sudo systemctl restart php8.1-fpm
Comandos de Depuración
# Test PHP-FPM configuration
sudo php-fpm8.1 -t
# Run PHP-FPM in foreground for debugging
sudo php-fpm8.1 -F
# Check loaded configuration
sudo php-fpm8.1 -i | grep "Configuration File"
# List all pools
sudo php-fpm8.1 -i | grep "\[pool"
# Monitor error log in real-time
sudo tail -f /var/log/php8.1-fpm.log
# Check system resource usage
sudo systemctl status php8.1-fpm
# Verify PHP modules
php -m
# Check PHP-FPM socket connections
sudo ss -xl | grep php
Analizar Problemas de Rendimiento
# Install and use PHP-FPM status monitoring
sudo apt install php-fpm-fcgi -y
# Get detailed status
sudo SCRIPT_NAME=/status SCRIPT_FILENAME=/status QUERY_STRING=full REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.1-fpm.sock
# Identify slow queries
sudo grep "executing too slow" /var/log/php-fpm/www-slow.log
# Check for memory issues
sudo dmesg | grep -i php
# Monitor in real-time with top
sudo top -p $(pgrep -d',' php-fpm)
Conclusión
PHP-FPM es una poderosa herramienta para gestionar procesos PHP con mejor rendimiento, seguridad y flexibilidad que el tradicional mod_php. Con la configuración adecuada y el monitoreo regular, puede manejar aplicaciones web de alto tráfico de manera eficiente.
Puntos Clave:
- PHP-FPM proporciona mejor rendimiento y escalabilidad que mod_php
- Los pools permiten aislar diferentes sitios web con configuraciones únicas
- La configuración adecuada de pm.max_children es crucial para el rendimiento
- El monitoreo regular ayuda a identificar cuellos de botella
- La configuración de seguridad previene muchas vulnerabilidades comunes
- Los Unix sockets son generalmente más rápidos que los TCP sockets para configuraciones de servidor único
Mejores Prácticas:
- Siempre probar los cambios de configuración antes de aplicarlos en producción
- Monitorear el uso de recursos y ajustar la configuración del pool en consecuencia
- Usar pools separados para sitios web diferentes
- Habilitar OPcache para mejor rendimiento
- Implementar logging apropiado para depuración
- Realizar copias de seguridad de configuraciones antes de modificarlas
- Mantener PHP y PHP-FPM actualizados
- Revisar regularmente logs lentos para optimizar código
Próximos Pasos:
- Implementar múltiples versiones de PHP con PHP-FPM
- Configurar balanceo de carga con múltiples servidores PHP-FPM
- Integrar herramientas de monitoreo como New Relic o Datadog
- Implementar caché con Redis o Memcached
- Optimizar consultas de base de datos
- Configurar ajuste automático basado en métricas de rendimiento
Recuerda que la configuración óptima depende de tu carga de trabajo específica, recursos del servidor y requisitos de la aplicación. Monitorea regularmente y ajusta según sea necesario.


