TL;DR — Kurzzusammenfassung

Nginx als Reverse Proxy und Load Balancer mit SSL einrichten. Behandelt proxy_pass, Let's Encrypt, Balancing-Algorithmen, WebSocket, Caching und Rate-Limiting.

Nginx betreibt über 34 % der meistbesuchten Websites der Welt — und ein großer Teil dieses Datenverkehrs fließt durch ihn nicht als Webserver, sondern als Reverse Proxy und Load Balancer. Nginx als Reverse Proxy mit SSL-Termination zu konfigurieren, bietet einen einzigen gehärteten Einstiegspunkt, der die Last auf Backend-Server verteilt, TLS von Ihrer Anwendung abnimmt und Caching, Rate Limiting und Sicherheits-Header an einem Ort hinzufügt. Diese Anleitung deckt jede Schicht dieses Stacks ab: Grundlagen des Reverse Proxy, SSL-Termination mit Let’s Encrypt, alle vier Load-Balancing-Algorithmen, WebSocket-Proxying, Response-Caching, Rate Limiting, Sicherheits-Header, HTTP/2 und HTTP/3, Monitoring und ein praxisnahes Node.js-Cluster-Szenario.

Voraussetzungen

Stellen Sie sicher, dass Sie folgendes haben:

  • Ubuntu 22.04 oder 24.04 (Befehle gelten für jede Debian-basierte Distribution)
  • Nginx 1.18 oder höher (sudo apt install nginx)
  • Eine registrierte Domain, die auf die öffentliche IP Ihres Servers zeigt
  • Terminalzugriff mit sudo-Rechten
  • Mindestens zwei Backend-Anwendungsserver oder -Prozesse (für Load Balancing)

Grundlagen des Reverse Proxy

Ein Reverse Proxy befindet sich zwischen dem Internet und einem oder mehreren Backend-Servern. Clients verbinden sich mit Nginx; Nginx leitet die Anfrage an das entsprechende Backend weiter und gibt die Antwort zurück. Der Backend-Server benötigt niemals eine öffentliche IP-Adresse.

Die zentrale Direktive ist proxy_pass:

server {
    listen 80;
    server_name app.beispiel.de;

    location / {
        proxy_pass http://127.0.0.1:3000;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Die vier proxy_set_header-Direktiven sind in jeder Produktionskonfiguration unerlässlich. Ohne X-Forwarded-For zeigen Ihre Anwendungslogs nur die IP des Nginx-Servers. Ohne X-Forwarded-Proto kann Ihre App HTTP von HTTPS nicht unterscheiden und kann fehlerhafte Redirect-Schleifen erzeugen.

Legen Sie sinnvolle Timeouts fest, damit langsame Backends keine Nginx-Worker blockieren:

proxy_connect_timeout 10s;
proxy_send_timeout    60s;
proxy_read_timeout    60s;
proxy_buffering       on;
proxy_buffer_size     8k;
proxy_buffers         8 16k;

SSL-Termination mit Let’s Encrypt

SSL-Termination bedeutet, dass Nginx den TLS-Handshake verwaltet und einfaches HTTP an Backends im internen Netzwerk weiterleitet — ohne TLS-Overhead auf den einzelnen Anwendungsservern.

Installieren Sie Certbot mit dem Nginx-Plugin:

sudo apt install certbot python3-certbot-nginx -y

Erhalten und installieren Sie ein Zertifikat (Certbot ändert Ihren server-Block automatisch):

sudo certbot --nginx -d app.beispiel.de -d www.app.beispiel.de

Certbot erstellt einen systemd-Timer, der Zertifikate automatisch vor dem Ablauf erneuert:

sudo systemctl status certbot.timer
sudo certbot renew --dry-run

Load-Balancing-Algorithmen

Um die Last auf mehrere Backends zu verteilen, ersetzen Sie das einzelne proxy_pass-Ziel durch einen upstream-Block:

upstream app_cluster {
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
    server 10.0.0.12:3000;
}

Round-Robin (Standard)

Keine Direktive erforderlich. Nginx verteilt Anfragen sequenziell auf alle Upstream-Server. Fügen Sie Gewichte hinzu, um mehr Datenverkehr zu leistungsfähigeren Knoten zu leiten:

upstream app_cluster {
    server 10.0.0.10:3000 weight=3;
    server 10.0.0.11:3000 weight=1;
    server 10.0.0.12:3000 weight=1;
}

Wenigste Verbindungen (least_conn)

Nginx leitet jede neue Anfrage an den Upstream-Server mit den wenigsten aktiven Verbindungen weiter. Ideal für Workloads mit variablen Antwortzeiten:

upstream app_cluster {
    least_conn;
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
    server 10.0.0.12:3000;
}

IP-Hash (ip_hash)

Die Client-IP bestimmt, welches Backend alle Anfragen von diesem Client bedient. Nützlich für Session-Persistenz ohne gemeinsamen Session-Speicher:

upstream app_cluster {
    ip_hash;
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
    server 10.0.0.12:3000;
}

Zufällig (random)

Nginx wählt ein Backend zufällig aus. Mit dem Parameter two wählt es zwei Server zufällig und leitet an den mit weniger Verbindungen weiter:

upstream app_cluster {
    random two least_conn;
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
    server 10.0.0.12:3000;
}

Upstream-Gesundheitsprüfungen

Markieren Sie Server als Backup oder setzen Sie Fehlerschwellenwerte, damit Nginx aufhört, Datenverkehr an nicht verfügbare Backends zu senden:

upstream app_cluster {
    least_conn;
    server 10.0.0.10:3000 max_fails=3 fail_timeout=30s;
    server 10.0.0.11:3000 max_fails=3 fail_timeout=30s;
    server 10.0.0.12:3000 backup;
}

WebSocket-Proxying

WebSocket-Verbindungen erfordern einen HTTP/1.1-Upgrade-Handshake. Fügen Sie drei Direktiven zu jedem location-Block hinzu, der WebSocket-Datenverkehr weiterleitet:

location /ws/ {
    proxy_pass http://app_cluster;

    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_read_timeout 3600s;

    proxy_set_header Host              $host;
    proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Caching mit proxy_cache

Nginx kann Upstream-Antworten im Arbeitsspeicher oder auf der Festplatte zwischenspeichern, was die Backend-Last bei cachebaren Endpunkten erheblich reduziert.

Definieren Sie eine Cache-Zone im http-Kontext:

http {
    proxy_cache_path /var/cache/nginx
                     levels=1:2
                     keys_zone=app_cache:10m
                     max_size=1g
                     inactive=60m
                     use_temp_path=off;
}

Aktivieren Sie Caching im location-Block:

location /api/public/ {
    proxy_pass         http://app_cluster;
    proxy_cache        app_cache;
    proxy_cache_valid  200 10m;
    proxy_cache_valid  404  1m;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    add_header         X-Cache-Status $upstream_cache_status;
}

Rate Limiting

Rate Limiting schützt Backends vor Traffic-Spitzen und Brute-Force-Angriffen. Definieren Sie eine gemeinsame Speicherzone im http-Kontext:

http {
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/m;
}

Wenden Sie die Zone auf einen location an:

location /api/ {
    limit_req zone=api_limit burst=10 nodelay;
    limit_req_status 429;
    proxy_pass http://app_cluster;
}

Sicherheits-Header

Fügen Sie Sicherheits-Header im server-Block hinzu:

server {
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
    server_tokens off;
}

HTTP/2 und HTTP/3

Aktivieren Sie HTTP/2 in der listen-Direktive:

listen 443 ssl http2;

Für HTTP/3 (Nginx 1.25+):

listen 443 ssl http2;
listen 443 quic reuseport;
add_header Alt-Svc 'h3=":443"; ma=86400' always;

Monitoring mit stub_status

Aktivieren Sie das stub_status-Modul, um Echtzeit-Verbindungsmetriken bereitzustellen:

server {
    listen 127.0.0.1:8080;

    location /nginx_status {
        stub_status;
        allow 127.0.0.1;
        deny all;
    }
}
curl http://127.0.0.1:8080/nginx_status

Vergleich: Nginx vs. Alternativen

FunktionNginxHAProxyTraefikCaddy
ProtokollunterstützungHTTP, HTTPS, TCP, UDPHTTP, HTTPS, TCPHTTP, HTTPS, TCP, gRPCHTTP, HTTPS
Balancing-AlgorithmenRR, LC, IP-Hash, randomRR, LC, source, URIRR, WRRRR, LC
Aktive Health-ChecksNur Nginx PlusJa (eingebaut)Ja (eingebaut)Ja (eingebaut)
Auto-SSL (ACME)Via CertbotVia CertbotEingebautEingebaut
Eingebautes CachingJaNeinNeinNein
HTTP/31.25+ (experimentell)NeinNeinJa
Am besten fürWeb + Proxy + CacheReines TCP/HTTP-LBKubernetes-IngressEinfaches Auto-SSL

Praxisszenario: Load Balancing eines Node.js-Clusters mit SSL

Sie haben eine produktive Node.js-API, die drei PM2-Prozesse auf demselben Host ausführt (Ports 3001, 3002, 3003). Sie möchten sie als api.beispiel.de über HTTPS mit Session-Affinität, Rate Limiting am Authentifizierungsendpunkt und WebSocket-Unterstützung bereitstellen.

upstream node_api {
    ip_hash;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    server 127.0.0.1:3003;
}

limit_req_zone $binary_remote_addr zone=auth_limit:5m  rate=5r/m;
limit_req_zone $binary_remote_addr zone=api_limit:10m  rate=60r/m;

server {
    listen 443 ssl http2;
    server_name api.beispiel.de;

    ssl_certificate     /etc/letsencrypt/live/api.beispiel.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.beispiel.de/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;

    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    server_tokens off;

    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
        limit_req_status 429;
        proxy_pass         http://node_api;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api/auth/ {
        limit_req zone=auth_limit burst=3 nodelay;
        limit_req_status 429;
        proxy_pass         http://node_api;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /ws/ {
        proxy_pass         http://node_api;
        proxy_http_version 1.1;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_read_timeout 3600s;
    }
}

server {
    listen 80;
    server_name api.beispiel.de;
    return 301 https://$host$request_uri;
}

Häufige Fehler und Sonderfälle

Der abschließende Schrägstrich in proxy_pass ist wichtig. proxy_pass http://backend; behält den vollständigen URI einschließlich des /api/-Präfixes. proxy_pass http://backend/; entfernt das location-Präfix und kann schwer zu diagnostizierende 404-Fehler verursachen.

Verwenden Sie ip_hash nicht, wenn ein CDN vor Nginx liegt. Aller CDN-Traffic scheint von einer kleinen Menge von CDN-IP-Adressen zu kommen, sodass ip_hash den gesamten CDN-Traffic an ein einzelnes Backend sendet.

Lange Verbindungen und SSE erfordern größere Timeouts. Server-Sent Events (SSE) und Long-Polling-Verbindungen bleiben auf unbestimmte Zeit offen. Passen Sie proxy_read_timeout an das Heartbeat-Intervall Ihrer Anwendung plus einen Puffer an.

proxy_buffering und Streaming. Wenn Ihr Backend eine Antwort streamt (SSE, Chunked Transfer), setzen Sie proxy_buffering off für diesen location. Andernfalls puffert Nginx die vollständige Antwort, bevor er sie sendet, was den Zweck des Streamings zunichte macht.

Fehlerbehebung

502 Bad Gateway. Das Backend läuft nicht oder hört nicht auf dem konfigurierten Port. Prüfen Sie: sudo systemctl status ihre-app, ss -tlnp | grep 3000.

504 Gateway Timeout. Das Backend antwortet zu langsam. Erhöhen Sie proxy_read_timeout oder untersuchen Sie die Backend-Performance.

WebSocket-Verbindungen brechen nach 60 Sekunden ab. Nginx’s Standard-proxy_read_timeout beträgt 60 Sekunden. Erhöhen Sie ihn für WebSocket-locations.

Cache funktioniert nicht. Stellen Sie sicher, dass proxy_cache_path im http-Kontext definiert ist, das Verzeichnis existiert und vom nginx-Benutzer beschreibbar ist, und dass proxy_cache im richtigen location-Block konfiguriert ist.

Zusammenfassung

Nginx als Reverse Proxy und Load Balancer bietet eine produktionsreife Traffic-Schicht ohne zusätzliche Infrastruktur. Wichtigste Erkenntnisse:

  • Setzen Sie immer X-Forwarded-For, X-Forwarded-Proto und Host in jedem Proxy-location
  • Verwenden Sie certbot --nginx für unterbrechungsfreie SSL-Zertifikatsbereitstellung mit automatischer Erneuerung
  • Wählen Sie least_conn für APIs, ip_hash für Session-Persistenz und random two least_conn für große Backend-Pools
  • Markieren Sie Backends mit max_fails und fail_timeout, damit Nginx nicht verfügbare Server automatisch entfernt
  • Verwenden Sie proxy_http_version 1.1 mit Upgrade/Connection-Headern für WebSocket-Proxying
  • Aktivieren Sie proxy_cache für öffentliche Endpunkte und limit_req_zone zum Schutz von Authentifizierungsrouten
  • Aktivieren Sie http2 in der listen-Direktive für Multiplexing; evaluieren Sie quic bei Nginx 1.25+

Verwandte Artikel