Zum Inhalt springen

NGINX-Konfiguration

Das Cloud-Init-Provisioning stellt eine vollständig leistungsoptimierte NGINX-CDN-Edge-Konfiguration bereit. Diese Seite dokumentiert jede Konfigurationsschicht, von der Kernel-Optimierung über das Cache-Verhalten bis hin zur Vendor-Header-Injection. Alle Einstellungen wurden in einem 48-stündigen kontinuierlichen Lasttest mit einem Spitzenwert von 172.540 req/s verifiziert.

DateiZweck
/etc/sysctl.d/99-cdn-tuning.confLinux-Kernel-Netzwerkoptimierung
/etc/systemd/system/nginx.service.d/override.confDateideskriptor-Limits für NGINX
/etc/security/limits.d/99-nginx.confBetriebssystem-Limits für den www-data-Benutzer
/etc/nginx/nginx.confNGINX-Hauptkonfiguration (Worker, Buffer, Gzip, Logging)
/etc/nginx/conf.d/cdn-edge.confCDN-Proxy-Konfiguration (Cache, Upstream, Header)

Wird beim Booten über /etc/sysctl.d/99-cdn-tuning.conf angewendet.

ParameterWertStandardZweck
net.core.somaxconn655354096Listen-Backlog-Warteschlangengröße
net.core.netdev_max_backlog655351000Pro-CPU eingehender Paket-Backlog
net.ipv4.tcp_max_syn_backlog65535256SYN-Anforderungswarteschlange (verhindert Drops bei Lastspitzen)
net.ipv4.tcp_tw_reuse12Wiederverwendung von TIME_WAIT-Sockets für ausgehende Verbindungen
net.ipv4.ip_local_port_range1024-6553532768-60999Ephemerer Portbereich (64K vs. 28K)
net.core.rmem_max16 MB212 KBMaximaler Empfangs-Socket-Buffer
net.core.wmem_max16 MB212 KBMaximaler Sende-Socket-Buffer
net.ipv4.tcp_rmem4K/87K/16M4K/131K/6MPro-Socket-Empfangsbuffer (Min/Standard/Max)
net.ipv4.tcp_wmem4K/65K/16M4K/16K/4MPro-Socket-Sendebuffer (Min/Standard/Max)
net.ipv4.tcp_fin_timeout1560FIN_WAIT_2-Timeout (schnellere Socket-Bereinigung)
net.ipv4.tcp_keepalive_time3007200Keepalive-Probes nach 5 Min. Leerlauf starten
net.ipv4.tcp_slow_start_after_idle01Congestion Window bei inaktiven Verbindungen warmhalten
net.ipv4.tcp_max_tw_buckets2000000~65536Maximale TIME_WAIT-Sockets
fs.file-max2097152variiertSystemweites Dateideskriptor-Limit
vm.swappiness1060RAM gegenüber Swap für Cache-Daten bevorzugen
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
}

Das Systemd-Override unter /etc/systemd/system/nginx.service.d/override.conf setzt LimitNOFILE=65535 entsprechend.

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

Die Busy-Buffer-Größe von 256k ist entscheidend — sie muss die größte gecachte Antwort übersteigen (Juice Shop ist 75 KB). Die ursprüngliche 64k-Einstellung verursachte Serialisierung unter Last.

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;

Speichert Dateideskriptoren und Metadaten für gecachte Objekte zwischen und eliminiert damit stat()- und open()-Syscalls bei häufig abgerufenen Dateien.

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

Bei 90K req/s mit keepalive_requests 1000 wurden Verbindungen alle 11 Sekunden recycelt, was TIME_WAIT-Sockets erzeugte. Die Erhöhung auf 100.000 eliminierte dies vollständig.

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;

Das cdn-Logformat enthält $upstream_cache_status (HIT/MISS) und $request_time für die Latenzanalyse. Gepuffertes Logging (256k/5s Flush) reduziert den I/O-Overhead unter hoher Last.

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

Mit 4 Workern × 256 Keepalive = 1.024 warme Verbindungen zum Origin. In Kombination mit proxy_http_version 1.1 und proxy_set_header Connection "" wird der TCP-Handshake-Overhead bei jedem Cache-Miss eliminiert.

proxy_cache_path /var/cache/nginx/cdn
levels=1:2
keys_zone=cdn_cache:32m
max_size=25g
inactive=24h
use_temp_path=off;
ParameterWertZweck
keys_zone=cdn_cache:32m32 MB Shared MemorySpeichert ~256.000 Cache-Schlüssel und Metadaten
max_size=25g25 GB FestplattenlimitNutzt den Großteil der 30 GB OS-Festplatte; LRU-Eviction bei Erreichen des Limits
inactive=24h24-Stunden-Inaktivitäts-TimeoutNicht innerhalb von 24h abgerufene Inhalte werden entfernt (nicht identisch mit TTL)
use_temp_path=offDirekt ins Cache-Verzeichnis schreibenVermeidet dateisystemübergreifende Dateiverschiebungen
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;
DirektiveWertZweck
proxy_cache_valid 200 301 302 4h4-Stunden-TTLGecachte Inhalte sind 4 Stunden gültig (erhöht, um Durchsatzeinbrüche bei Refresh-Wellen zu reduzieren)
proxy_cache_lock onThundering-Herd-PräventionNur 1 Anfrage geht pro ungecachter URL zum Origin; andere warten auf die Cache-Befüllung
proxy_cache_lock_age 3sLock-TimeoutFalls die erste Anfrage nach 3s nicht abgeschlossen ist, wird eine weitere durchgelassen
proxy_cache_background_update onLatenzfreie AktualisierungLiefert sofort veraltete Inhalte aus, während im Hintergrund aktualisiert wird
proxy_cache_use_staleAusfallsicherheitLiefert veraltete Inhalte während Origin-Fehlern (500/502/503/504) oder während der Aktualisierung
proxy_ignore_headersCaching erzwingenIgnoriert Origin Set-Cookie, Cache-Control, Expires, Vary — das CDN bestimmt TTL und Vary-Verhalten (Juice Shop sendet max-age=0 und dreifache Vary-Header, die effektives Caching verhinderten)
proxy_hide_header X-Cache-StatusOrigin-Header entfernenOrigin-NGINX fügt einen eigenen X-Cache-Status hinzu — wird entfernt, damit nur der Cache-Status des CDN sichtbar ist
proxy_hide_header VaryCache-Fragmentierung verhindernOrigin sendet mehrere Vary: Accept-Encoding-Header. Das Entfernen verhindert die Cache-Schlüssel-Fragmentierung über Accept-Encoding-Permutationen. NGINXs gzip_vary on fügt automatisch den korrekten einzelnen Vary-Header hinzu
proxy_read_timeout 30s;
proxy_connect_timeout 10s;
proxy_send_timeout 15s;

Gibt dem Origin unter Last mehr Antwortzeit und schlägt dennoch bei Verbindungsproblemen schnell fehl.

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

reuseport aktiviert SO_REUSEPORT — der Kernel verteilt eingehende Verbindungen direkt auf die Worker-Prozesse und eliminiert damit Accept-Mutex-Konflikte.

Der Simulator injiziert Header von allen fünf großen CDN-Anbietern gleichzeitig. Dies ermöglicht es, F5 XC mit dem “Trusted Client IP Header” eines beliebigen Anbieters zu konfigurieren und realistische Header-Payloads zu sehen, unabhängig davon, welches CDN simuliert wird.

HeaderWertZweck
X-Forwarded-ForClient-IP-KetteStandard-Weiterleitungs-IP
X-Forwarded-Protohttp oder httpsUrsprüngliches Client-Protokoll
X-Forwarded-HostUrsprünglicher HostnameUrsprünglicher Host-Header
X-Forwarded-PortServer-PortUrsprünglicher Port
X-Real-IPClient-IPEinzelne Client-IP (Nginx-Konvention)
Via1.1 cdn-simulatorProxy-Identifikation
ForwardedRFC 7239-FormatStandardisierter Weiterleitungs-Header
CDN-Loopcdn-simulatorSchleifenerkennung
HeaderWertZweck
True-Client-IPClient-IPUrsprüngliche Endbenutzer-IP-Adresse
X-Akamai-EdgescapeZusammengesetzter Geo-Stringgeoregion, 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-CharacteristicsGeräteeigenschaftenbrand_name, model_name, is_mobile, is_tablet, is_wireless_device, device_os, device_os_version, resolution_width, resolution_height
X-Akamai-Request-IDRequest-UUIDEindeutiger Anfrage-Identifikator
HeaderWertZweck
CF-Connecting-IPClient-IPEchte Client-IP (immer vorhanden)
CF-IPCountryUSZweistelliger Ländercode
cf-ipcitySan JoseClient-Stadt
cf-ipcontinentNAKontinent-Code
cf-iplatitude / cf-iplongitudeKoordinatenGeolokalisierung
cf-region / cf-region-codeCalifornia / CARegionsinformationen
cf-metro-code807US-Metropolcode
cf-postal-code95113Postleitzahl
cf-timezoneAmerica/Los_AngelesIANA-Zeitzone
Cf-Ray{request_id}-SJCEindeutige Ray-ID mit POP-IATA-Code
CF-Visitor{"scheme":"https"}Besucher-Protokollinformationen
cf-bot-score85Bot-Score (1=Bot, 99=Mensch)
cf-verified-botfalseBekannter guter Bot-Indikator
cf-ja3-hashe7d705a3286e19ea42f587b344ee6865JA3-TLS-Fingerprint
cf-ja4t13d1516h2_8daaf6152771_b0da82dd1658JA4-TLS-Fingerprint
HeaderWertZweck
CloudFront-Viewer-AddressIP:PortClient-IP und Quellport
CloudFront-Viewer-CountryUSLändercode
CloudFront-Viewer-Country-NameUnited StatesVollständiger Ländername
CloudFront-Viewer-Country-RegionCARegionscode
CloudFront-Viewer-Country-Region-NameCaliforniaVollständiger Regionsname
CloudFront-Viewer-CitySan JoseClient-Stadt
CloudFront-Viewer-Postal-Code95113Postleitzahl
CloudFront-Viewer-Latitude / Longitude37.33530 / -121.89300Geolokalisierung
CloudFront-Viewer-Time-ZoneAmerica/Los_AngelesIANA-Zeitzone
CloudFront-Viewer-Metro-Code807US-Metropolcode
CloudFront-Viewer-ASN7018Autonome Systemnummer
CloudFront-Viewer-Http-Version2.0Client-HTTP-Version
CloudFront-Forwarded-ProtohttpsUrsprüngliches Protokoll
CloudFront-Viewer-TLSTLSv1.3:TLS_AES_128_GCM_SHA256:sessionResumedTLS-Details
CloudFront-Viewer-JA3-Fingerprinte7d705a3286e19ea42f587b344ee6865JA3-TLS-Fingerprint
CloudFront-Is-Desktop-Viewertrue/falseGeräteerkennung
CloudFront-Is-Mobile-Viewertrue/falseGeräteerkennung
CloudFront-Is-Tablet-Viewertrue/falseGeräteerkennung
CloudFront-Is-SmartTV-ViewerfalseGeräteerkennung
X-Amz-Cf-IdKodierte IDCloudFront-Anfrage-Identifikator
HeaderWertZweck
Fastly-Client-IPClient-IPEchte Client-IP
Fastly-SSL1Verbindung war über TLS
Fastly-Client1Client-seitige Anfrage (nicht Shield)
Fastly-FFcache-sjc3120-SJCCache-Node-Identifikation
X-Geo-Country-CodeUSLand (VCL-Variablen-Konvention)
X-Geo-Country-Code3USADreistelliger Ländercode
X-Geo-Country-NameUnited StatesVollständiger Ländername
X-Geo-CitySan JoseClient-Stadt
X-Geo-RegionCARegionscode
X-Geo-Continent-CodeNAKontinent
X-Geo-Latitude / X-Geo-Longitude37.3353 / -121.8938Geolokalisierung
X-Geo-Postal-Code95113Postleitzahl
X-Geo-Metro-Code807US-Metropolcode
X-Geo-ASN7018Autonome Systemnummer
X-Geo-Conn-SpeedbroadbandVerbindungsgeschwindigkeitsklasse
X-Geo-Conn-TypewiredVerbindungstyp
HeaderWertZweck
X-Azure-ClientIPClient-IPClient-IP-Adresse
X-Azure-SocketIPClient-IPTCP-Socket-Quell-IP
X-Azure-RefKodierter ReferenzstringEindeutige Anfrage-Referenz zur Fehlerbehebung
X-Azure-FDIDa0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1Front-Door-Ressourcen-Identifikator
X-Azure-RequestChainhops=1Schleifen-Erkennung Hop-Zähler
HeaderWerteZweck
X-Cache-StatusHIT, MISS, EXPIRED, STALE, UPDATINGCache-Verhalten für diese Anfrage
X-CDN-Edgecdn-simulatorIdentifiziert diesen Edge-Knoten
X-CDN-POPSJCSimulierter Point of Presence IATA-Code
X-Served-Bycache-sjc3120-SJCSimulierter Cache-Knoten im Fastly-Format
X-Request-IDUUID (pro Anfrage)Eindeutiger Anfrage-Identifikator

Der Simulator erkennt den Gerätetyp aus dem User-Agent-Header mithilfe von NGINX-map-Direktiven:

  • Mobil: Erkennt iPhone, Android (kein Tablet), iPod, BlackBerry, Opera Mini, IEMobile
  • Tablet: Erkennt iPad, Android-Tablet, Kindle, PlayBook
  • Desktop: Standard, wenn weder Mobil noch Tablet zutrifft

Der Gerätetyp wird widergespiegelt in:

  • CloudFront-Is-Desktop-Viewer / CloudFront-Is-Mobile-Viewer / CloudFront-Is-Tablet-Viewer
  • X-Akamai-Device-Characteristics (is_mobile, is_tablet, is_wireless_device-Felder)
Terminal-Fenster
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

Alternativ origin_host in terraform.tfvars aktualisieren und terraform apply ausführen, um neu zu provisionieren.

Terminal-Fenster
ssh azureuser@<PUBLIC_IP>
sudo rm -rf /var/cache/nginx/cdn/*
sudo systemctl reload nginx
Terminal-Fenster
# 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
Terminal-Fenster
# 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

Verifiziert in einem 48-stündigen kontinuierlichen Lasttest:

MetrikWert
Spitzendurchsatz (gecacht)172.540 req/s
Dauerdurchsatz (gecacht)85.000-103.000 req/s
Spitzenverbindungen15.000 gleichzeitig
Cache-Trefferquote100% (nach Aufwärmung)
Speicher unter Last1,2 GB stabil (8% von 16 GB)
CPU bei Spitzenlast100% (4 Kerne - CPU ist die Obergrenze)
Fehler während 48h-Test0
SpeicherlecksKeine erkannt
VerbindungslecksKeine erkannt