- Inicio
- Simulador CDN
- Configuración de NGINX
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.
Archivos de Configuración
Sección titulada «Archivos de Configuración»| Archivo | Propósito |
|---|---|
/etc/sysctl.d/99-cdn-tuning.conf | Ajuste de red del kernel Linux |
/etc/systemd/system/nginx.service.d/override.conf | Límites de descriptores de archivo para NGINX |
/etc/security/limits.d/99-nginx.conf | Límites a nivel de SO para el usuario www-data |
/etc/nginx/nginx.conf | Configuración principal de NGINX (workers, buffers, gzip, logging) |
/etc/nginx/conf.d/cdn-edge.conf | Configuración de proxy CDN (caché, upstream, cabeceras) |
Ajuste del Kernel
Sección titulada «Ajuste del Kernel»Aplicado mediante /etc/sysctl.d/99-cdn-tuning.conf en el arranque.
| Parámetro | Valor | Predeterminado | Propósito |
|---|---|---|---|
net.core.somaxconn | 65535 | 4096 | Tamaño de la cola de backlog de escucha |
net.core.netdev_max_backlog | 65535 | 1000 | Backlog de paquetes entrantes por CPU |
net.ipv4.tcp_max_syn_backlog | 65535 | 256 | Cola de solicitudes SYN (previene descartes bajo ráfagas) |
net.ipv4.tcp_tw_reuse | 1 | 2 | Reutilizar sockets TIME_WAIT para conexiones salientes |
net.ipv4.ip_local_port_range | 1024-65535 | 32768-60999 | Rango de puertos efímeros (64K vs 28K) |
net.core.rmem_max | 16 MB | 212 KB | Buffer máximo de socket de recepción |
net.core.wmem_max | 16 MB | 212 KB | Buffer máximo de socket de envío |
net.ipv4.tcp_rmem | 4K/87K/16M | 4K/131K/6M | Buffer de recepción por socket (mín/predeterminado/máx) |
net.ipv4.tcp_wmem | 4K/65K/16M | 4K/16K/4M | Buffer de envío por socket (mín/predeterminado/máx) |
net.ipv4.tcp_fin_timeout | 15 | 60 | Tiempo de espera FIN_WAIT_2 (limpieza de sockets más rápida) |
net.ipv4.tcp_keepalive_time | 300 | 7200 | Iniciar sondas keepalive después de 5 min de inactividad |
net.ipv4.tcp_slow_start_after_idle | 0 | 1 | Mantener la ventana de congestión activa en conexiones inactivas |
net.ipv4.tcp_max_tw_buckets | 2000000 | ~65536 | Máximo de sockets TIME_WAIT |
fs.file-max | 2097152 | varía | Límite de descriptores de archivo a nivel de sistema |
vm.swappiness | 10 | 60 | Preferir RAM sobre swap para datos de caché |
Configuración Principal de NGINX
Sección titulada «Configuración Principal de NGINX»Workers y Conexiones
Sección titulada «Workers y Conexiones»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.
Buffers de Proxy
Sección titulada «Buffers de Proxy»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 readingEl 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.
Compresión Gzip
Sección titulada «Compresión Gzip»gzip on;gzip_comp_level 4; # Balance: ~85% of max compression at ~40% CPUgzip_min_length 256; # Skip tiny responses (gzip header overhead)gzip_vary on; # Vary: Accept-Encoding for correct cachinggzip_proxied any; # Compress all proxied responsesgzip_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;Caché de Archivos Abiertos
Sección titulada «Caché de Archivos Abiertos»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 del Cliente
Sección titulada «Keepalive del Cliente»keepalive_timeout 65;keepalive_requests 100000; # Was 1000 — caused connection recycling at 90K req/sA 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.
Registro de Acceso
Sección titulada «Registro de Acceso»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.
Keepalive Upstream
Sección titulada «Keepalive Upstream»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é.
Configuración de Caché
Sección titulada «Configuración de Caché»Ruta de Caché
Sección titulada «Ruta 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ámetro | Valor | Propósito |
|---|---|---|
keys_zone=cdn_cache:32m | 32 MB de memoria compartida | Almacena ~256,000 claves de caché y metadatos |
max_size=25g | Límite de disco de 25 GB | Utiliza la mayor parte del disco de SO de 30 GB; expulsión LRU al alcanzar el límite |
inactive=24h | Tiempo de espera de inactividad de 24 horas | El contenido no accedido durante 24h se expulsa (no es lo mismo que TTL) |
use_temp_path=off | Escribir directamente en el directorio de caché | Evita movimientos de archivos entre sistemas de archivos |
Comportamiento de Caché
Sección titulada «Comportamiento de Caché»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;| Directiva | Valor | Propósito |
|---|---|---|
proxy_cache_valid 200 301 302 4h | TTL de 4 horas | El contenido cacheado es válido por 4 horas (aumentado para reducir caídas de rendimiento por oleadas de actualización) |
proxy_cache_lock on | Prevención de thundering herd | Solo 1 solicitud va al origen por URL no cacheada; las demás esperan el llenado de caché |
proxy_cache_lock_age 3s | Tiempo de espera del bloqueo | Si la primera solicitud no se ha completado en 3s, se permite pasar otra |
proxy_cache_background_update on | Actualización sin latencia | Sirve contenido obsoleto inmediatamente mientras se actualiza en segundo plano |
proxy_cache_use_stale | Resiliencia | Sirve contenido obsoleto durante errores del origen (500/502/503/504) o durante la actualización |
proxy_ignore_headers | Forzar cacheo | Ignora 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-Status | Eliminar cabecera del origen | El 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 Vary | Prevenir 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 |
Tiempos de Espera del Proxy
Sección titulada «Tiempos de Espera del Proxy»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.
Bloque Server
Sección titulada «Bloque Server»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.
Cabeceras de Proveedores CDN
Sección titulada «Cabeceras de Proveedores CDN»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)»| Cabecera | Valor | Propósito |
|---|---|---|
X-Forwarded-For | Cadena de IP del cliente | IP reenviada estándar |
X-Forwarded-Proto | http o https | Protocolo original del cliente |
X-Forwarded-Host | Nombre de host original | Cabecera Host original |
X-Forwarded-Port | Puerto del servidor | Puerto original |
X-Real-IP | IP del cliente | IP única del cliente (convención de nginx) |
Via | 1.1 cdn-simulator | Identificación del proxy |
Forwarded | Formato RFC 7239 | Cabecera de reenvío estandarizada |
CDN-Loop | cdn-simulator | Detección de bucles |
Cabeceras de Akamai
Sección titulada «Cabeceras de Akamai»| Cabecera | Valor | Propósito |
|---|---|---|
True-Client-IP | IP del cliente | Dirección IP original del usuario final |
X-Akamai-Edgescape | Cadena geográfica compuesta | georegion, 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-Characteristics | Propiedades del dispositivo | brand_name, model_name, is_mobile, is_tablet, is_wireless_device, device_os, device_os_version, resolution_width, resolution_height |
X-Akamai-Request-ID | UUID de solicitud | Identificador único de solicitud |
Cabeceras de Cloudflare
Sección titulada «Cabeceras de Cloudflare»| Cabecera | Valor | Propósito |
|---|---|---|
CF-Connecting-IP | IP del cliente | IP verdadera del cliente (siempre presente) |
CF-IPCountry | US | Código de país de dos letras |
cf-ipcity | San Jose | Ciudad del cliente |
cf-ipcontinent | NA | Código de continente |
cf-iplatitude / cf-iplongitude | Coordenadas | Geolocalización |
cf-region / cf-region-code | California / CA | Información de región |
cf-metro-code | 807 | Código metro de EE. UU. |
cf-postal-code | 95113 | Código postal |
cf-timezone | America/Los_Angeles | Zona horaria IANA |
Cf-Ray | {request_id}-SJC | ID ray único con código IATA del POP |
CF-Visitor | {"scheme":"https"} | Información de protocolo del visitante |
cf-bot-score | 85 | Puntuación de bot (1=bot, 99=humano) |
cf-verified-bot | false | Indicador de bot conocido legítimo |
cf-ja3-hash | e7d705a3286e19ea42f587b344ee6865 | Huella digital TLS JA3 |
cf-ja4 | t13d1516h2_8daaf6152771_b0da82dd1658 | Huella digital TLS JA4 |
Cabeceras de Amazon CloudFront
Sección titulada «Cabeceras de Amazon CloudFront»| Cabecera | Valor | Propósito |
|---|---|---|
CloudFront-Viewer-Address | IP:puerto | IP del cliente y puerto de origen |
CloudFront-Viewer-Country | US | Código de país |
CloudFront-Viewer-Country-Name | United States | Nombre completo del país |
CloudFront-Viewer-Country-Region | CA | Código de región |
CloudFront-Viewer-Country-Region-Name | California | Nombre completo de la región |
CloudFront-Viewer-City | San Jose | Ciudad del cliente |
CloudFront-Viewer-Postal-Code | 95113 | Código postal |
CloudFront-Viewer-Latitude / Longitude | 37.33530 / -121.89300 | Geolocalización |
CloudFront-Viewer-Time-Zone | America/Los_Angeles | Zona horaria IANA |
CloudFront-Viewer-Metro-Code | 807 | Código metro de EE. UU. |
CloudFront-Viewer-ASN | 7018 | Número de Sistema Autónomo |
CloudFront-Viewer-Http-Version | 2.0 | Versión HTTP del cliente |
CloudFront-Forwarded-Proto | https | Protocolo original |
CloudFront-Viewer-TLS | TLSv1.3:TLS_AES_128_GCM_SHA256:sessionResumed | Detalles TLS |
CloudFront-Viewer-JA3-Fingerprint | e7d705a3286e19ea42f587b344ee6865 | Huella digital TLS JA3 |
CloudFront-Is-Desktop-Viewer | true/false | Detección de dispositivo |
CloudFront-Is-Mobile-Viewer | true/false | Detección de dispositivo |
CloudFront-Is-Tablet-Viewer | true/false | Detección de dispositivo |
CloudFront-Is-SmartTV-Viewer | false | Detección de dispositivo |
X-Amz-Cf-Id | ID codificado | Identificador de solicitud de CloudFront |
Cabeceras de Fastly
Sección titulada «Cabeceras de Fastly»| Cabecera | Valor | Propósito |
|---|---|---|
Fastly-Client-IP | IP del cliente | IP verdadera del cliente |
Fastly-SSL | 1 | La conexión fue sobre TLS |
Fastly-Client | 1 | Solicitud orientada al cliente (no shield) |
Fastly-FF | cache-sjc3120-SJC | Identificación del nodo de caché |
X-Geo-Country-Code | US | País (convención de variable VCL) |
X-Geo-Country-Code3 | USA | Código de país de tres letras |
X-Geo-Country-Name | United States | Nombre completo del país |
X-Geo-City | San Jose | Ciudad del cliente |
X-Geo-Region | CA | Código de región |
X-Geo-Continent-Code | NA | Continente |
X-Geo-Latitude / X-Geo-Longitude | 37.3353 / -121.8938 | Geolocalización |
X-Geo-Postal-Code | 95113 | Código postal |
X-Geo-Metro-Code | 807 | Código metro de EE. UU. |
X-Geo-ASN | 7018 | Número de Sistema Autónomo |
X-Geo-Conn-Speed | broadband | Clase de velocidad de conexión |
X-Geo-Conn-Type | wired | Tipo de conexión |
Cabeceras de Azure Front Door
Sección titulada «Cabeceras de Azure Front Door»| Cabecera | Valor | Propósito |
|---|---|---|
X-Azure-ClientIP | IP del cliente | Dirección IP del cliente |
X-Azure-SocketIP | IP del cliente | IP de origen del socket TCP |
X-Azure-Ref | Cadena de referencia codificada | Referencia única de solicitud para resolución de problemas |
X-Azure-FDID | a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1 | Identificador del recurso Front Door |
X-Azure-RequestChain | hops=1 | Conteo 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)»| Cabecera | Valores | Propósito |
|---|---|---|
X-Cache-Status | HIT, MISS, EXPIRED, STALE, UPDATING | Comportamiento de caché para esta solicitud |
X-CDN-Edge | cdn-simulator | Identifica este nodo de borde |
X-CDN-POP | SJC | Código IATA del Punto de Presencia simulado |
X-Served-By | cache-sjc3120-SJC | Nodo de caché simulado en formato Fastly |
X-Request-ID | UUID (por solicitud) | Identificador único de solicitud |
Detección de Dispositivos
Sección titulada «Detección de Dispositivos»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-ViewerX-Akamai-Device-Characteristics(camposis_mobile,is_tablet,is_wireless_device)
Operaciones
Sección titulada «Operaciones»Cambiar el Servidor de Origen
Sección titulada «Cambiar el Servidor de Origen»ssh azureuser@<PUBLIC_IP>
# Update upstream serversudo sed -i 's|server .*;|server NEW_HOST:80;|' /etc/nginx/conf.d/cdn-edge.conf
# Clear cache and reloadsudo rm -rf /var/cache/nginx/cdn/*sudo nginx -t && sudo systemctl reload nginxO actualice origin_host en terraform.tfvars y ejecute terraform apply para reaprovisionar.
Limpiar la Caché
Sección titulada «Limpiar la Caché»ssh azureuser@<PUBLIC_IP>sudo rm -rf /var/cache/nginx/cdn/*sudo systemctl reload nginxVerificar Estadísticas de Caché
Sección titulada «Verificar Estadísticas de Caché»# Object count and disk usagesudo find /var/cache/nginx/cdn -type f | wc -lsudo du -sh /var/cache/nginx/cdn
# Recent access log with cache statustail -20 /var/log/nginx/access.logMonitoreo Bajo Carga
Sección titulada «Monitoreo Bajo Carga»# Real-time connections and socket statesss -s
# NGINX worker CPU usagetop -bn1 | grep nginx
# Upstream keepalive connectionsss -tn state established dst <ORIGIN_IP> | wc -l
# TIME_WAIT socket countss -tn state time-wait | wc -lResultados de Pruebas de Rendimiento
Sección titulada «Resultados de Pruebas de Rendimiento»Verificado bajo prueba de carga continua de 48 horas:
| Métrica | Valor |
|---|---|
| Rendimiento pico (cacheado) | 172,540 req/s |
| Rendimiento sostenido (cacheado) | 85,000-103,000 req/s |
| Conexiones pico | 15,000 concurrentes |
| Ratio de aciertos de caché | 100% (cuando está calentada) |
| Memoria bajo carga | 1.2 GB estable (8% de 16 GB) |
| CPU en pico | 100% (4 núcleos - la CPU es el techo) |
| Errores durante la prueba de 48h | 0 |
| Fugas de memoria | No detectadas |
| Fugas de conexiones | No detectadas |