Ir al contenido

Configuración de NGINX

El aprovisionamiento cloud-init despliega una configuración de borde CDN NGINX completamente optimizada para rendimiento. Esta página documenta cada capa de configuración, desde el ajuste del kernel hasta el comportamiento de caché y la inyección de cabeceras de proveedores. Todos los ajustes fueron verificados bajo una prueba de carga continua de 48 horas con pico de 172,540 req/s.

ArchivoPropósito
/etc/sysctl.d/99-cdn-tuning.confAjuste de red del kernel Linux
/etc/systemd/system/nginx.service.d/override.confLímites de descriptores de archivo para NGINX
/etc/security/limits.d/99-nginx.confLímites a nivel de SO para el usuario www-data
/etc/nginx/nginx.confConfiguración principal de NGINX (workers, buffers, gzip, logging)
/etc/nginx/conf.d/cdn-edge.confConfiguración de proxy CDN (caché, upstream, cabeceras)

Aplicado mediante /etc/sysctl.d/99-cdn-tuning.conf en el arranque.

ParámetroValorPredeterminadoPropósito
net.core.somaxconn655354096Tamaño de la cola de backlog de escucha
net.core.netdev_max_backlog655351000Backlog de paquetes entrantes por CPU
net.ipv4.tcp_max_syn_backlog65535256Cola de solicitudes SYN (previene descartes bajo ráfagas)
net.ipv4.tcp_tw_reuse12Reutilizar sockets TIME_WAIT para conexiones salientes
net.ipv4.ip_local_port_range1024-6553532768-60999Rango de puertos efímeros (64K vs 28K)
net.core.rmem_max16 MB212 KBBuffer máximo de socket de recepción
net.core.wmem_max16 MB212 KBBuffer máximo de socket de envío
net.ipv4.tcp_rmem4K/87K/16M4K/131K/6MBuffer de recepción por socket (mín/predeterminado/máx)
net.ipv4.tcp_wmem4K/65K/16M4K/16K/4MBuffer de envío por socket (mín/predeterminado/máx)
net.ipv4.tcp_fin_timeout1560Tiempo de espera FIN_WAIT_2 (limpieza de sockets más rápida)
net.ipv4.tcp_keepalive_time3007200Iniciar sondas keepalive después de 5 min de inactividad
net.ipv4.tcp_slow_start_after_idle01Mantener la ventana de congestión activa en conexiones inactivas
net.ipv4.tcp_max_tw_buckets2000000~65536Máximo de sockets TIME_WAIT
fs.file-max2097152varíaLímite de descriptores de archivo a nivel de sistema
vm.swappiness1060Preferir RAM sobre swap para datos de caché
worker_processes auto; # 4 workers on D4s_v5 (1 per vCPU)
worker_rlimit_nofile 65535; # Per-worker file descriptor limit
events {
use epoll; # Linux-optimized event model
worker_connections 8192; # 4 workers x 8192 = 32,768 max concurrent
multi_accept on; # Accept all pending connections per event loop
accept_mutex off; # Not needed with epoll + reuseport
}

El override de Systemd en /etc/systemd/system/nginx.service.d/override.conf establece LimitNOFILE=65535 para coincidir.

proxy_buffering on;
proxy_buffer_size 16k; # Header buffer (handles large CDN headers)
proxy_buffers 64 16k; # 1 MB per connection (64 x 16k)
proxy_busy_buffers_size 256k; # Can send 256k to client while still reading

El tamaño del busy buffer de 256k es crítico — debe exceder la respuesta cacheada más grande (Juice Shop es 75 KB). La configuración original de 64k causaba serialización bajo carga.

gzip on;
gzip_comp_level 4; # Balance: ~85% of max compression at ~40% CPU
gzip_min_length 256; # Skip tiny responses (gzip header overhead)
gzip_vary on; # Vary: Accept-Encoding for correct caching
gzip_proxied any; # Compress all proxied responses
gzip_types text/plain text/css text/javascript text/xml
application/json application/javascript application/xml
application/xml+rss application/atom+xml
application/ld+json application/manifest+json
image/svg+xml;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;

Cachea descriptores de archivo y metadatos para objetos cacheados, eliminando llamadas al sistema stat() y open() en archivos frecuentes.

keepalive_timeout 65;
keepalive_requests 100000; # Was 1000 — caused connection recycling at 90K req/s

A 90K req/s con keepalive_requests 1000, las conexiones se reciclaban cada 11 segundos, generando sockets TIME_WAIT. Aumentar a 100,000 eliminó esto por completo.

log_format cdn '$remote_addr [$time_local] "$request" $status $body_bytes_sent $upstream_cache_status $request_time';
access_log /var/log/nginx/access.log cdn buffer=256k flush=5s;

El formato de log cdn incluye $upstream_cache_status (HIT/MISS) y $request_time para análisis de latencia. El logging con buffer (256k/flush cada 5s) reduce la sobrecarga de E/S bajo alta carga.

upstream origin_backend {
server 20.12.78.159:80;
keepalive 256; # Persistent connections per worker to origin
keepalive_timeout 60s;
keepalive_requests 1000;
}

Con 4 workers x 256 keepalive = 1,024 conexiones activas al origen. Combinado con proxy_http_version 1.1 y proxy_set_header Connection "", esto elimina la sobrecarga del handshake TCP en cada fallo de caché.

proxy_cache_path /var/cache/nginx/cdn
levels=1:2
keys_zone=cdn_cache:32m
max_size=25g
inactive=24h
use_temp_path=off;
ParámetroValorPropósito
keys_zone=cdn_cache:32m32 MB de memoria compartidaAlmacena ~256,000 claves de caché y metadatos
max_size=25gLímite de disco de 25 GBUtiliza la mayor parte del disco de SO de 30 GB; expulsión LRU al alcanzar el límite
inactive=24hTiempo de espera de inactividad de 24 horasEl contenido no accedido durante 24h se expulsa (no es lo mismo que TTL)
use_temp_path=offEscribir directamente en el directorio de cachéEvita movimientos de archivos entre sistemas de archivos
proxy_cache cdn_cache;
proxy_cache_valid 200 301 302 4h;
proxy_cache_valid 404 1m;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_lock on;
proxy_cache_lock_age 3s;
proxy_cache_lock_timeout 3s;
proxy_cache_background_update on;
proxy_cache_use_stale updating error timeout http_500 http_502 http_503 http_504;
proxy_ignore_headers Set-Cookie Cache-Control Expires Vary;
proxy_hide_header X-Cache-Status;
proxy_hide_header Vary;
DirectivaValorPropósito
proxy_cache_valid 200 301 302 4hTTL de 4 horasEl contenido cacheado es válido por 4 horas (aumentado para reducir caídas de rendimiento por oleadas de actualización)
proxy_cache_lock onPrevención de thundering herdSolo 1 solicitud va al origen por URL no cacheada; las demás esperan el llenado de caché
proxy_cache_lock_age 3sTiempo de espera del bloqueoSi la primera solicitud no se ha completado en 3s, se permite pasar otra
proxy_cache_background_update onActualización sin latenciaSirve contenido obsoleto inmediatamente mientras se actualiza en segundo plano
proxy_cache_use_staleResilienciaSirve contenido obsoleto durante errores del origen (500/502/503/504) o durante la actualización
proxy_ignore_headersForzar cacheoIgnora Set-Cookie, Cache-Control, Expires, Vary del origen — el CDN decide el TTL y el comportamiento de Vary (Juice Shop envía max-age=0 y cabeceras Vary triples que impedían un cacheo efectivo)
proxy_hide_header X-Cache-StatusEliminar cabecera del origenEl NGINX de origen agrega su propio X-Cache-Status — se elimina para que solo sea visible el estado de caché del CDN
proxy_hide_header VaryPrevenir fragmentación de cachéEl origen envía múltiples cabeceras Vary: Accept-Encoding. Eliminarlas previene la fragmentación de claves de caché entre permutaciones de Accept-Encoding. El gzip_vary on de NGINX agrega automáticamente la cabecera Vary correcta y única
proxy_read_timeout 30s;
proxy_connect_timeout 10s;
proxy_send_timeout 15s;

Da al origen más tiempo de respuesta bajo carga mientras falla rápidamente en problemas de conexión.

server {
listen 80 reuseport; # Kernel distributes connections across all 4 workers
server_name _;
}

reuseport habilita SO_REUSEPORT — el kernel distribuye las conexiones entrantes directamente a los procesos worker, eliminando la contención del mutex de aceptación.

El simulador inyecta cabeceras de los cinco principales proveedores CDN simultáneamente. Esto permite configurar F5 XC con la “Trusted Client IP Header” de cualquier proveedor y ver cargas útiles de cabeceras realistas independientemente del CDN que se esté simulando.

Cabeceras Estándar de la Industria (Todos los CDN)

Sección titulada «Cabeceras Estándar de la Industria (Todos los CDN)»
CabeceraValorPropósito
X-Forwarded-ForCadena de IP del clienteIP reenviada estándar
X-Forwarded-Protohttp o httpsProtocolo original del cliente
X-Forwarded-HostNombre de host originalCabecera Host original
X-Forwarded-PortPuerto del servidorPuerto original
X-Real-IPIP del clienteIP única del cliente (convención de nginx)
Via1.1 cdn-simulatorIdentificación del proxy
ForwardedFormato RFC 7239Cabecera de reenvío estandarizada
CDN-Loopcdn-simulatorDetección de bucles
CabeceraValorPropósito
True-Client-IPIP del clienteDirección IP original del usuario final
X-Akamai-EdgescapeCadena geográfica compuestageoregion, country_code, region_code, city, dma, pmsa, msa, areacode, county, fips, lat, long, timezone, zip, continent, throughput, bw, network, asnum, network_type
X-Akamai-Device-CharacteristicsPropiedades del dispositivobrand_name, model_name, is_mobile, is_tablet, is_wireless_device, device_os, device_os_version, resolution_width, resolution_height
X-Akamai-Request-IDUUID de solicitudIdentificador único de solicitud
CabeceraValorPropósito
CF-Connecting-IPIP del clienteIP verdadera del cliente (siempre presente)
CF-IPCountryUSCódigo de país de dos letras
cf-ipcitySan JoseCiudad del cliente
cf-ipcontinentNACódigo de continente
cf-iplatitude / cf-iplongitudeCoordenadasGeolocalización
cf-region / cf-region-codeCalifornia / CAInformación de región
cf-metro-code807Código metro de EE. UU.
cf-postal-code95113Código postal
cf-timezoneAmerica/Los_AngelesZona horaria IANA
Cf-Ray{request_id}-SJCID ray único con código IATA del POP
CF-Visitor{"scheme":"https"}Información de protocolo del visitante
cf-bot-score85Puntuación de bot (1=bot, 99=humano)
cf-verified-botfalseIndicador de bot conocido legítimo
cf-ja3-hashe7d705a3286e19ea42f587b344ee6865Huella digital TLS JA3
cf-ja4t13d1516h2_8daaf6152771_b0da82dd1658Huella digital TLS JA4
CabeceraValorPropósito
CloudFront-Viewer-AddressIP:puertoIP del cliente y puerto de origen
CloudFront-Viewer-CountryUSCódigo de país
CloudFront-Viewer-Country-NameUnited StatesNombre completo del país
CloudFront-Viewer-Country-RegionCACódigo de región
CloudFront-Viewer-Country-Region-NameCaliforniaNombre completo de la región
CloudFront-Viewer-CitySan JoseCiudad del cliente
CloudFront-Viewer-Postal-Code95113Código postal
CloudFront-Viewer-Latitude / Longitude37.33530 / -121.89300Geolocalización
CloudFront-Viewer-Time-ZoneAmerica/Los_AngelesZona horaria IANA
CloudFront-Viewer-Metro-Code807Código metro de EE. UU.
CloudFront-Viewer-ASN7018Número de Sistema Autónomo
CloudFront-Viewer-Http-Version2.0Versión HTTP del cliente
CloudFront-Forwarded-ProtohttpsProtocolo original
CloudFront-Viewer-TLSTLSv1.3:TLS_AES_128_GCM_SHA256:sessionResumedDetalles TLS
CloudFront-Viewer-JA3-Fingerprinte7d705a3286e19ea42f587b344ee6865Huella digital TLS JA3
CloudFront-Is-Desktop-Viewertrue/falseDetección de dispositivo
CloudFront-Is-Mobile-Viewertrue/falseDetección de dispositivo
CloudFront-Is-Tablet-Viewertrue/falseDetección de dispositivo
CloudFront-Is-SmartTV-ViewerfalseDetección de dispositivo
X-Amz-Cf-IdID codificadoIdentificador de solicitud de CloudFront
CabeceraValorPropósito
Fastly-Client-IPIP del clienteIP verdadera del cliente
Fastly-SSL1La conexión fue sobre TLS
Fastly-Client1Solicitud orientada al cliente (no shield)
Fastly-FFcache-sjc3120-SJCIdentificación del nodo de caché
X-Geo-Country-CodeUSPaís (convención de variable VCL)
X-Geo-Country-Code3USACódigo de país de tres letras
X-Geo-Country-NameUnited StatesNombre completo del país
X-Geo-CitySan JoseCiudad del cliente
X-Geo-RegionCACódigo de región
X-Geo-Continent-CodeNAContinente
X-Geo-Latitude / X-Geo-Longitude37.3353 / -121.8938Geolocalización
X-Geo-Postal-Code95113Código postal
X-Geo-Metro-Code807Código metro de EE. UU.
X-Geo-ASN7018Número de Sistema Autónomo
X-Geo-Conn-SpeedbroadbandClase de velocidad de conexión
X-Geo-Conn-TypewiredTipo de conexión
CabeceraValorPropósito
X-Azure-ClientIPIP del clienteDirección IP del cliente
X-Azure-SocketIPIP del clienteIP de origen del socket TCP
X-Azure-RefCadena de referencia codificadaReferencia única de solicitud para resolución de problemas
X-Azure-FDIDa0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1Identificador del recurso Front Door
X-Azure-RequestChainhops=1Conteo de saltos para detección de bucles

Cabeceras de Respuesta (Agregadas a las Respuestas del Cliente)

Sección titulada «Cabeceras de Respuesta (Agregadas a las Respuestas del Cliente)»
CabeceraValoresPropósito
X-Cache-StatusHIT, MISS, EXPIRED, STALE, UPDATINGComportamiento de caché para esta solicitud
X-CDN-Edgecdn-simulatorIdentifica este nodo de borde
X-CDN-POPSJCCódigo IATA del Punto de Presencia simulado
X-Served-Bycache-sjc3120-SJCNodo de caché simulado en formato Fastly
X-Request-IDUUID (por solicitud)Identificador único de solicitud

El simulador detecta el tipo de dispositivo a partir de la cabecera User-Agent usando directivas map de NGINX:

  • Móvil: Coincide con iPhone, Android (no tablet), iPod, BlackBerry, Opera Mini, IEMobile
  • Tablet: Coincide con iPad, tablet Android, Kindle, PlayBook
  • Escritorio: Predeterminado cuando no coincide ni móvil ni tablet

El tipo de dispositivo se refleja en:

  • CloudFront-Is-Desktop-Viewer / CloudFront-Is-Mobile-Viewer / CloudFront-Is-Tablet-Viewer
  • X-Akamai-Device-Characteristics (campos is_mobile, is_tablet, is_wireless_device)
Ventana de terminal
ssh azureuser@<PUBLIC_IP>
# Update upstream server
sudo sed -i 's|server .*;|server NEW_HOST:80;|' /etc/nginx/conf.d/cdn-edge.conf
# Clear cache and reload
sudo rm -rf /var/cache/nginx/cdn/*
sudo nginx -t && sudo systemctl reload nginx

O actualice origin_host en terraform.tfvars y ejecute terraform apply para reaprovisionar.

Ventana de terminal
ssh azureuser@<PUBLIC_IP>
sudo rm -rf /var/cache/nginx/cdn/*
sudo systemctl reload nginx
Ventana de terminal
# Object count and disk usage
sudo find /var/cache/nginx/cdn -type f | wc -l
sudo du -sh /var/cache/nginx/cdn
# Recent access log with cache status
tail -20 /var/log/nginx/access.log
Ventana de terminal
# Real-time connections and socket states
ss -s
# NGINX worker CPU usage
top -bn1 | grep nginx
# Upstream keepalive connections
ss -tn state established dst <ORIGIN_IP> | wc -l
# TIME_WAIT socket count
ss -tn state time-wait | wc -l

Verificado bajo prueba de carga continua de 48 horas:

MétricaValor
Rendimiento pico (cacheado)172,540 req/s
Rendimiento sostenido (cacheado)85,000-103,000 req/s
Conexiones pico15,000 concurrentes
Ratio de aciertos de caché100% (cuando está calentada)
Memoria bajo carga1.2 GB estable (8% de 16 GB)
CPU en pico100% (4 núcleos - la CPU es el techo)
Errores durante la prueba de 48h0
Fugas de memoriaNo detectadas
Fugas de conexionesNo detectadas