Parámetros Fundamentales en la Configuración de Nginx
Para exprimir al máximo el rendimiento de Nginx en entornos de alta concurrencia, es crucial ajustar correctamente su archivo de configuración principal. A continuación, se detallan las directivas más críticas:
Gestión de Procesos y Afinidad de CPU
- worker_processes: Define la cantidad de procesos de trabajo. La práctica recomendada es utilizar
autopara que Nginx genere un proceso por cada núcleo lógico disponible, o establecerlo manualmente como un múltiplo del número de núcleos físicos. - worker_cpu_affinity: Permite anclar procesos a núcleos específicos mediante máscaras de bits. En kernels modernos, el planificador del sistema operativo suele gestionar esto de manera eficiente, pero en cargas extremas, fijar la afinidad puede reducir los fallos de caché de la CPU.
- worker_rlimit_nofile: Establece el límite máximo de descriptores de archivo que un proceso de Nginx puede abrir. Este valor debe ser igual o ligeramente inferior al límite global del sistema operativo (configurable mediante
ulimit -n).
Para verificar el límite de descriptores de archivo a nivel de kernel en Linux:
cat /proc/sys/fs/file-max
# Salida esperada en sistemas optimizados: 1048576 o superior
Modelos de Eventos y Conexiones
Nginx adapta su modelo de procesamiento según el sistema operativo. En Linux, es imperativo utilizar epoll, que ofrece un rendimiento superior al manejar miles de conexiones simultáneas en comparación con los modelos estándar como select o poll. Para sistemas BSD o macOS, se debe emplear kqueue.
- worker_connections: Determina el número máximo de conexiones simultáneas que cada proceso de trabajo puede manejar. La capacidad teórica total del servidor es el producto de
worker_processesmultiplicado porworker_connections. - keepalive_timeout: Tiempo en segundos que una conexión persistente se mantiene abierta antes de cerrarse. Un valor entre 15 y 65 segundos suele ser óptimo para equilibrar la reutilización de conexiones y la liberación de recursos.
Búferes y Caché de Archivos
- client_header_buffer_size: Tamaño del búfer para las cabeceras de las peticiones del cliente. Se recomienda alinearlo con el tamaño de página del sistema (
getconf PAGESIZE, usualmente 4k). - open_file_cache: Almacena en memoria los descriptores de archivos abiertos, rutas de directorios y errores de "archivo no encontrado". Parámetros como
max(capacidad de la caché) einactive(tiempo de expiración) deben ajustarse según la frecuencia de acceso a los archivos estáticos. - open_file_cache_valid: Intervalo de tiempo para verificar si los elementos almacenados en la caché siguen siendo válidos.
Ajustes del Kernel Linux (sysctl)
El kernel de Linux tiene límites conservadores por defecto. Para soportar decenas de miles de conexiones concurrentes, es necesario modificar los parámetros de red y memoria en /etc/sysctl.conf.
Parámetros TCP y de Red Críticos
- net.ipv4.tcp_max_tw_buckets: Controla el número máximo de sockets en estado TIME-WAIT. Un valor bajo puede causar advertencias, mientras que uno muy alto consume memoria.
- net.ipv4.ip_local_port_range: Amplía el rango de puertos efímeros disponibles para conexiones salientes, evitando el agotamiento de puertos en servidores proxy inversos.
- net.ipv4.tcp_tw_reuse: Permite reutilizar sockets en estado TIME-WAIT para nuevas conexiones salientes cuando es seguro hacerlo según las marcas de tiempo. (Nota:
tcp_tw_recycleha sido deprecado y eliminado en kernels modernos debido a problemas con NAT). - net.ipv4.tcp_syncookies: Activa la protección contra ataques de inundación SYN, respondiendo con cookies criptográficas cuando la cola de SYN se desborda.
- net.core.somaxconn: Define el límite spuerior para la cola de conexiones entrantes (backlog). Nginx suele configurar su backlog en 511 por defecto, por lo que el kernel debe permitir al menos ese valor, idealmente mucho más.
Configuración Integral de sysctl
Edite el archivo /etc/sysctl.conf y añada o modifique los siguientes parámetros:
# Optimización de red y TCP
net.ipv4.ip_local_port_range = 10000 65535
net.ipv4.tcp_max_tw_buckets = 1440000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
# Colas y backlog
net.core.somaxconn = 65536
net.core.netdev_max_backlog = 65536
net.ipv4.tcp_max_orphans = 327680
# Buffers de memoria TCP
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 16384 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 8388608
net.core.wmem_default = 8388608
Para aplicar los cambios de inmediato sin reiniciar el servidor, ejecute:
sysctl -p
Gestión de Límites de Recursos del Sistema (ulimit)
Por defecto, muchas distribuciones de Linux limitan la cantidad de archivos abiertos y procesos por usuario a 1024. En un servidor web de alto tráfico, esto provocará rápidamente el error too many open files (demasiados archivos abiertos).
Para solucionar esto de forma persistente, edite el archivo /etc/security/limits.conf y agregue las siguientes líneas al final del documento. Asegúrese de reemplazar www-data por el usuario bajo el cual corre Nginx:
www-data soft nofile 1048576
www-data hard nofile 1048576
www-data soft nproc 1048576
www-data hard nproc 1048576
* soft nofile 1048576
* hard nofile 1048576
Los límites soft representan el valor efectivo actual, mientras que los hard actúan como un techo que solo el usuario root puede elevar. Tras modificar este archivo, es necesario cerrar y volver a abrir la sesión de la terminal para que los cambios surtan efecto.
Ejemplo de Configuración Integral de Nginx
A continuación, se presenta un archivo nginx.conf estructurado para maximizar el rendimiento, utilizando registro en formato JSON y caché de FastCGI:
user www-data;
worker_processes auto;
worker_cpu_affinity auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
worker_rlimit_nofile 1048576;
events {
use epoll;
worker_connections 65535;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format json_logs escape=json '{'
'"time":"$time_iso8601",'
'"client_ip":"$remote_addr",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"bytes_sent":$body_bytes_sent,'
'"referer":"$http_referer",'
'"user_agent":"$http_user_agent",'
'"response_time":$request_time'
'}';
access_log /var/log/nginx/access.log json_logs;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 16M;
client_header_buffer_size 4k;
large_client_header_buffers 4 16k;
# Compresión Gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Configuración de Caché FastCGI
fastcgi_cache_path /var/cache/nginx/fcgi levels=1:2 keys_zone=FCGI_CACHE:50m max_size=2g inactive=60m use_temp_path=off;
open_file_cache max=200000 inactive=60s;
open_file_cache_valid 120s;
open_file_cache_min_uses 2;
server {
listen 80 default_server;
server_name api.production.local;
root /var/www/app/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Integración de Caché
fastcgi_cache FCGI_CACHE;
fastcgi_cache_valid 200 30m;
fastcgi_cache_valid 404 1m;
fastcgi_cache_bypass $http_cache_control;
fastcgi_no_cache $http_cache_control;
add_header X-FastCGI-Cache $upstream_cache_status;
}
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
}
}
Directivas de FastCGI y Ajustes de PHP-FPM
Cuando Nginx actúa como proxy inverso para aplicaciones PHP a través de FastCGI, la configuración de los tiempos de espera y búferes es vital para evitar errores 502 Bad Gateway y reducir la carga de la CPU.
- fastcgi_connect_timeout: Tiempo máximo para establecer la conexión con el proceso PHP-FPM.
- fastcgi_send_timeout y fastcgi_read_timeout: Tiempos límite para la transmisión de la petición y la recepción de la respuesta, respectivamente. Deben ajustarse según la latencia esperada de la aplicación.
- fastcgi_buffer_size y fastcgi_buffers: Definen la memoria asignada para leer la respuesta del backend. Si la respuesta excede estos búferes en memoria, Nginx comenzará a escribir en archivos temporales en disco, lo cual degrada el rendimiento.
- fastcgi_cache: Habilita el almacenamiento en caché de las respuestas de PHP. Esto es extremadamente eficaz para contenido dinámico que no cambia en cada petición, reduciendo drásticamente el consumo de CPU del servidor de aplicaciones.
Además de Nginx, el propio gestor de procesos PHP-FPM requiere ajustes en su archivo de configuración (por ejemplo, www.conf) para soportar alta concurrencia:
; Número máximo de procesos hijos concurrentes
pm.max_children = 150
; Límite de descriptores de archivo para el pool de FPM
rlimit_files = 1048576
; Cantidad de peticiones que un proceso manejará antes de ser reciclado
; Ayuda a prevenir fugas de memoria en aplicaciones PHP
pm.max_requests = 2000