Letzten Monat haben wir einem Kunden mit SaaS-Backend geholfen: 2 vCPU, 4 GB RAM, CPU dauerhaft bei 20 % – und jeden Nachmittag um 15 Uhr wurde die Website zur Diashow. In der Cloud-Überwachung stieß die ausgehende Bandbreite an die Obergrenze: 100 Mbps für volle vierzig Minuten ausgereizt. Sein erster Gedanke: „Ich brauche ein Upgrade.“ Wir öffneten die Nginx-Access-Logs und fanden, dass 70 % des Traffics unkomprimierte JSON-API-Antworten und statische JS-Dateien mit zufälligen ?v=-Parametern waren – dieselben Ressourcen wurden immer wieder vollständig ausgeliefert.
Nach Gzip, statischen Cache-Headern und upstream keepalive sank die Spitzenbandbreite auf 35 Mbps, die Ladezeit von 8 auf 1,2 Sekunden – ohne einen Cent mehr zu zahlen. Solche Geschichten sind auf kleinen VPS alltäglich: Der Engpass liegt in der Ausgangsbandbreite, nicht in der Rechenleistung. Nginx als Reverse Proxy zwischen Nutzern und Backend ist der beste Hebel, um Bandbreite zu sparen – vorausgesetzt, Sie wissen, welche Schrauben Sie drehen müssen.
Dieser Artikel ist kein Nginx-Installationsguide, sondern eine in Produktion erprobte bandbreitenorientierte Tuning-Checkliste: erst diagnostizieren, dann komprimieren, cachen, schließlich Verbindungswiederverwendung und Puffer optimieren. Voraussetzung: Nginx als HTTPS-Reverse-Proxy auf Port 443 (ohne Firewall zuerst unseren UFW-Firewall-Leitfaden für Cloud-Server lesen – nur 22/80/443 öffnen, dann optimieren).
Warum reißt zuerst die Bandbreite, nicht die CPU?
Bei Cloud-VPS ist die Abrechnungsbandbreite oft asymmetrisch: Kleine Pakete bieten 100 Mbps Peak und 1–2 TB monatliches Volumen – klingt viel, aber eine unkomprimierte 500-KB-JSON-Antwort bei 200 Requests pro Sekunde ergibt theoretisch 800 Mbps Bedarf und sprengt das Limit sofort. Nginx bedient statische Dateien und einfaches Reverse Proxying mit geringer CPU-Last – daher das typische Bild: „CPU idle, Bandbreite voll.“
Ein weiterer Fehler: gesamten Traffic direkt zum Origin. Ohne CDN, ohne Browser-Cache, ohne proxy_cache lädt jeder Nutzer bei jedem Refresh bundle.js und logo.png erneut vom VPS. Die http-Module in der offiziellen Nginx-Dokumentation sind im Kern Werkzeuge, um weniger Bytes zu übertragen oder weniger Verbindungen aufzubauen – entscheidend ist die szenariogerechte Kombination, nicht eine Universal-Konfiguration vom Blog.
| Symptom | Häufige Ursache | Erste Maßnahme |
|---|---|---|
| Langsame API, hohe Bandbreite | JSON/HTML unkomprimiert | gzip / brotli aktivieren |
| Hoher Traffic beim Reload | Statische Assets ohne Cache-Control | expires + Dateinamen mit Hash |
| Viele Backend-Verbindungen | Neue upstream-TCP pro Request | keepalive-Pool |
| Große Downloads füllen Ausgang | Direkt vom Origin, kein Segment-Cache | CDN oder proxy_cache |
Schritt 1: Erst diagnostizieren, nicht blind upgraden
Bevor Sie die Konfiguration ändern, zehn Minuten investieren, um zu klären, wohin die Bandbreite fließt. Auf dem Server nutzen wir typischerweise:
# Live-Traffic pro Verbindung (apt install iftop) sudo iftop -i eth0 # Stündlich/täglich (vnstat) vnstat -h vnstat -d # Nginx Access-Log: größte URLs nach Volumen awk '{print $7, $10}' /var/log/nginx/access.log | \ awk '{a[$1]+=$2} END {for(i in a) print a[i], i}' | sort -rn | head -20 # Aktuelle ESTABLISHED-Verbindungen ss -s ss -tn state established | wc -l
Stehen /api/-URLs mit Antworten von mehreren hundert KB oben, ist Kompression Priorität Nr. 1. Sind es .js, .css, .woff2 mit durchgehend 200 (kein 304), fehlen Cache-Header. Unterscheiden Sie eingehend und ausgehend: DDoS oder Crawler füllen den Eingang – ein anderes Thema (Rate-Limiting, WAF, fail2ban). Dieser Artikel fokussiert auf Ausgangsoptimierung im Normalbetrieb.
Cloud-Bandbreitengrafiken haben 1–5 Minuten Aggregationsverzögerung – bei der Fehlersuche gilt iftop auf dem Server. Wenn SSH selbst hakt, lesen Sie unseren Leitfaden zur SSH-Verbindungsfehlerbehebung auf Linux-Servern, um Netzwerkprobleme auszuschließen.
Schritt 2: Gzip / Brotli – günstigste Bandbreitenreduktion
Textantworten (JSON, HTML, JS, CSS, SVG, XML) lassen sich typischerweise um 60–80 % verkleinern. Das eingebaute gzip-Modul braucht nur wenige Zeilen Konfiguration; der CPU-Overhead ist auf den meisten VPS vertretbar.
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5; # 6–9 lohnen abnehmend, 5 ist der Sweet Spot
gzip_min_length 256; # Kleine Antworten nicht komprimieren
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml
font/woff2;
Praxisdetails: Erstens sorgt gzip_proxied any dafür, dass auch proxied Backend-Inhalte komprimiert werden (Standard: nur direkte Antworten). Zweitens: JPEG/PNG/WebP und Video nicht gzipen – bereits komprimierte Binärdaten bringen kaum Gewinn und kosten CPU. Drittens mit curl -H 'Accept-Encoding: gzip' -I https://your.site/api/foo prüfen, ob Content-Encoding: gzip gesetzt ist.
Mit Brotli-Modul (manche Distributionen oder Self-Builds) sparen Sie bei gleicher Qualität weitere 15–20 % – ideal für textlastige APIs. Ohne Modul reicht stabiles gzip völlig aus.
Schritt 3: Statischer Cache und sendfile
Build-Tools (Vite, Webpack) hängen Content-Hashes an Dateinamen, z. B. app.a3f2b1.js. Solche Dateien können lang gecacht werden – der zweite Besuch lädt sie gar nicht mehr. Viele Teams hashen nur im Build, senden aber kein Cache-Control von Nginx – der Browser fordert jedes Mal alles neu an.
location ~* \.(js|css|woff2?|ttf|ico|svg)$ {
root /var/www/app/dist;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off; # Bei Cache-Hits access_log aus für weniger IO
}
# Im http-Block empfohlen
sendfile on;
tcp_nopush on;
tcp_nodelay on;
sendfile übergibt Dateiseiten direkt vom Kernel an den Socket und spart Userspace-Kopien – hilfreich bei großen statischen Dateien und vielen parallelen Downloads. Bei Kombination mit AIO oder Thread-Pools testen; für die meisten Sites reicht sendfile + tcp_nopush + tcp_nodelay.
HTML und index.html nicht mit immutable – sonst sehen Nutzer nach Deploys alte Shells. Üblich: gehashte Assets 30 Tage, HTML no-cache (Revalidierung erlaubt).
Schritt 4: Reverse-Proxy-Cache (proxy_cache)
Für read-heavy APIs (Konfigurationslisten, Kataloge, Artikeldetails) kann Nginx kurz cachen – Origin-Bandbreite geteilt durch Trefferquote. Eine der unterschätztesten Fähigkeiten des proxy-Moduls.
# http-Block proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=apicache:50m max_size=2g inactive=60m use_temp_path=off; upstream backend { server 127.0.0.1:3000; keepalive 32; # siehe nächster Abschnitt } server { location /api/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_cache apicache; proxy_cache_valid 200 5m; proxy_cache_key "$scheme$request_method$host$request_uri"; add_header X-Cache-Status $upstream_cache_status; proxy_buffering on; proxy_buffers 16 16k; proxy_busy_buffers_size 64k; } }
$upstream_cache_status zeigt HIT, MISS oder BYPASS – sofort sichtbar, ob der Cache greift. Schreiboperationen (POST/PUT/DELETE) müssen den Cache umgehen; personalisierte APIs mit Cookies vorsichtig behandeln, damit Nutzer A nicht die Daten von Nutzer B erhält.
Mit proxy_buffering on puffert Nginx die Backend-Antwort, bevor sie an den Client geht – bei langsamem Backend und schnellem Client werden Verbindungen nicht unnötig blockiert. Für SSE-Streams oder große Uploads: proxy_buffering off in der jeweiligen location.
Schritt 5: upstream keepalive – weniger TCP-Handshakes
Standardmäßig kann Nginx pro Client-Request eine neue TCP-Verbindung zum Backend öffnen. Bei hoher QPS fressen TIME_WAIT und Drei-Wege-Handshakes CPU und lokale Ports – Antworten werden langsamer, effektive Bandbreite sinkt. upstream keepalive hält einen Verbindungspool zum Backend; nach der Antwort geht die Verbindung zurück in den Pool.
upstream backend {
server 127.0.0.1:8080;
keepalive 64; # Poolgröße nach QPS anpassen
}
location / {
proxy_pass http://backend;
proxy_http_version 1.1; # HTTP/1.1 für keepalive nötig
proxy_set_header Connection ""; # Connection: close entfernen
}
Fehlt proxy_http_version 1.1 oder Connection "", wirkt keepalive nicht – der häufigste „konfiguriert, aber wirkungslos“-Fall in Kundenumgebungen. keepalive 64 reicht für die meisten Sites unter einer Million PV/Tag; zu groß belastet Backend-Dateideskriptoren.
Schritt 6: Worker, Verbindungen und Rate-Limiting
Bei voller Bandbreite prüfen, ob Nginx selbst zum Verbindungsengpass wird. Kernparameter auf oberster Ebene in nginx.conf:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
# Optional: Rate-Limit pro IP gegen Bandbreitenmonopole
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn:10m;
server {
limit_req zone=perip burst=20 nodelay;
limit_conn conn 50;
}
worker_connections × worker_processes muss über der Spitzenlast liegen. Bei 2 Kernen ist worker_processes auto meist 2 – 4096 × 2 = 8192 reicht für kleine bis mittlere Sites. fs.file-max und worker_rlimit_nofile abstimmen, sonst too many open files in den Logs.
limit_rate begrenzt einzelne Downloads; limit_req schützt APIs vor Missbrauch. Das „erzeugt“ keine Bandbreite, verhindert aber, dass wenige Ausreißer alle Nutzer ausbremsen – die letzte Schranke im Bandbreiten-Management.
Schritt 7: Wann lohnt sich ein CDN?
Wenn nach allen Optimierungen die Bandbreite periodisch an der Decke klebt, sind CDN oder ein größeres Paket fällig. Einfache Kriterien:
- Statische Assets > 60 % des Ausgangsverkehrs → CDN für JS/CSS/Bilder, Origin nur noch HTML und API
- Nutzer in mehreren Regionen → Edge-Knoten verkürzen die Distanz und entlasten den Origin
- Traffic-Spitzen (Kampagnen, Livestreams) → CDN trägt Peaks, kein teures Peak-Bandbreiten-Paket am Origin
Nach CDN-Einführung am Nginx: Origin nur CDN-IPs erlauben (Firewall-Whitelist) und echte Client-IP durchreichen (X-Forwarded-For / real_ip). Sonst umgehen Angreifer CDN-Schutz und -Cache per Direktzugriff auf die Origin-IP.
Vollständiger server-Block (Domain anpassen und deployen)
Alle Fragmente in ein minimales lauffähiges Beispiel – für Node-/Python-Backend auf 127.0.0.1:3000:
upstream app {
server 127.0.0.1:3000;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
gzip on;
gzip_types application/json application/javascript text/css text/plain;
gzip_min_length 256;
location /assets/ {
alias /var/www/app/dist/assets/;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location / {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
}
}
Danach sudo nginx -t && sudo systemctl reload nginx und im Browser-Network-Tab prüfen: 30-Tage-Cache für Assets, gzip für APIs. In unserer Release-Checkliste: curl -sI https://app.example.com/assets/main.js | grep -i cache.
Validierung und laufendes Monitoring
Tuning ist kein Einmalprojekt. In Grafana oder Cloud-Monitoring vier Kurven parallel beobachten: ausgehende Bandbreite, Nginx active connections, upstream-Antwortzeit, Cache-Trefferquote (mit proxy_cache). Vor Releases oder Traffic-Events Lasttest: ab -n 1000 -c 50 https://app.example.com/ oder hey -n 5000 -c 100 – Spitzenbandbreite und P95-Latenz vor/nach dem Tuning vergleichen.
Sinkt die Bandbreite, bleibt die Latenz aber hoch, liegt der Engpass eher bei Datenbank oder Disk-IO – ein anderes Kapitel. Mindestens wissen Sie: Geld in Indizes stecken, nicht blind 500 Mbps kaufen.
Jenseits des Tuning: Der richtige Standort spart Bandbreite
Nginx hilft, weniger Bytes zu senden – die physische Distanz Nutzer–Origin lässt sich nicht per Config wegkonfigurieren. APAC-Publikum auf einem US-East-VPS bedeutet hohe RTT, mehr Retransmits, schlechterer Durchsatz. Viele Teams legen Build und Preview auf Cloud-Mac oder nähere Knoten, Statik über Object Storage + CDN, Origin nur für APIs – die Bandbreitenrechnung sieht besser aus.
VPSSPark Mac mini M4 in der Cloud eignet sich für CI-Builds, interne Previews und Jump-Host-Ops: natives macOS, Terminal und OpenSSH out of the box; Standby ca. 4 W, ideal 7×24 als Relay oder Build-Maschine – sparsamer als ein weiterer x86-Kleinserver. Mit UFW nur auf 443 und Apps auf 127.0.0.1 sinken Angriffsfläche und Bandbreitenverschwendung.
Wenn Sie eine bandbreitenschonende, wartbare Architektur planen, ist VPSSPark Cloud Mac mini eine pragmatische Wahl als Low-Power-Jump- und Build-Knoten – Pakete ansehen – damit Ihr Nginx-Tuning nicht durch falsche Standortwahl zunichtegemacht wird.