Ein Nginx Reverse Proxy sitzt zwischen dem Internet und Ihren Backend-Anwendungen. Er nimmt jede Anfrage entgegen, beendet die TLS-Verschlüsselung, filtert Angriffe und reicht nur saubere Requests an Ihre Dienste weiter. Laut W3Techs läuft rund ein Drittel aller aktiven Websites auf Nginx, was den Server zur meistgenutzten Reverse-Proxy-Lösung im professionellen Hosting macht. Diese Anleitung führt Sie in zwölf Schritten von der leeren Ubuntu-Installation zu einem produktionsreifen Reverse Proxy mit HTTPS, Let’s-Encrypt-Zertifikat, modernen Sicherheits-Headern und Rate-Limiting.
Wir arbeiten mit Ubuntu 26.04 LTS (“Resolute Raccoon”, veröffentlicht am 23. April 2026), dem stabilen Nginx-Zweig und Certbot. Jeder Schritt enthält die exakten Befehle, vollständige Konfigurationsblöcke und Beispiel-Ausgaben. Am Ende finden Sie eine komplette Beispielkonfiguration, fünf häufige Stolperfallen, eine Troubleshooting-Tabelle mit acht Einträgen sowie fortgeschrittene Tipps für hohe Last und mehrere Backends.
Was ist ein Nginx Reverse Proxy und warum brauchen Sie ihn?
Ein Forward Proxy handelt im Auftrag des Clients, ein Reverse Proxy handelt im Auftrag des Servers. Der Client spricht ausschließlich mit Nginx und weiß nichts von den dahinterliegenden Anwendungen. Diese Architektur bringt vier konkrete Vorteile, die Sie in dieser Anleitung alle umsetzen.
TLS-Terminierung an einer Stelle. Ihre Node.js-, Python- oder PHP-Anwendung muss sich nicht um Zertifikate kümmern. Nginx beendet die HTTPS-Verbindung, das Backend bekommt entschlüsseltes HTTP auf localhost. Das spart Rechenzeit im Backend und zentralisiert die Zertifikatsverwaltung. Mehr zur Funktionsweise von Transportverschlüsselung lesen Sie in unserem Beitrag zu HTTPS und TLS.
Sicherheit und Angriffsfläche. Das Backend lauscht nur auf 127.0.0.1 und ist aus dem Internet nicht erreichbar. Nginx wird zur einzigen exponierten Komponente, die Sie härten, mit Rate-Limiting schützen und mit Sicherheits-Headern absichern. Eine kompromittierte Anwendung kann nicht direkt von außen erreicht werden.
Lastverteilung und Skalierung. Ein upstream-Block bündelt mehrere Backend-Instanzen. Nginx verteilt Anfragen per Round-Robin, Least-Connections oder IP-Hash und nimmt ausgefallene Knoten automatisch aus der Rotation. So skalieren Sie horizontal, ohne die Client-Konfiguration zu ändern.
Performance. Nginx liefert statische Dateien direkt aus, komprimiert Antworten mit Gzip oder Brotli, cached Responses und multiplext Verbindungen über HTTP/2 und HTTP/3. Das Backend wird entlastet und antwortet schneller. Genau diese Konstellation, ein einziger gehärteter Eingangspunkt vor beliebig vielen Diensten, macht den Reverse Proxy zum Standard moderner Web-Architekturen.
Voraussetzungen: Versionen und Systemanforderungen
Bevor Sie starten, brauchen Sie einen Server mit öffentlicher IP-Adresse und eine Domain, die Sie auf diese IP zeigen lassen können. Die folgende Tabelle listet alle Komponenten mit den in dieser Anleitung verwendeten Versionen. Halten Sie sich an aktuelle stabile Releases, da viele Sicherheitsfixes nur in neueren Versionen landen.
| Komponente | Version / Anforderung | Zweck |
|---|---|---|
| Betriebssystem | Ubuntu 26.04 LTS oder 24.04 LTS | Server-Basis (Debian funktioniert analog) |
| Nginx | Stabiler Zweig 1.28 oder neuer | Reverse Proxy, TLS, HTTP/2 und HTTP/3 |
| Certbot | 2.0 oder neuer (via snap) | Let’s-Encrypt-Zertifikate per ACME |
| OpenSSL | 3.0 oder neuer | TLS-Bibliothek, Schlüsselgenerierung |
| Domain | A/AAAA-Record auf Server-IP | Voraussetzung für HTTP-01-Validierung |
| Offene Ports | 80 (HTTP) und 443 (HTTPS) | ACME-Challenge und Produktivverkehr |
| Zugriff | SSH mit sudo-Rechten | Installation und Konfiguration |
Für den SSH-Zugang empfehlen wir Schlüssel statt Passwörter. Falls Sie noch keinen erzeugt haben, folgen Sie unserer Anleitung zum SSH-Key mit Ed25519. Prüfen Sie außerdem vorab, dass Ihre Domain bereits auf die Server-IP auflöst, sonst scheitert die Zertifikatsausstellung in Schritt 7.
Schritt 1: System aktualisieren und Nginx installieren
Bringen Sie zuerst das Paketverzeichnis auf den neuesten Stand und installieren Sie alle ausstehenden Sicherheitsupdates. Anschließend installieren Sie Nginx aus den Ubuntu-Repositories. Wer die allerneuesten Features benötigt, kann das offizielle Nginx-Repository einbinden, für die meisten Reverse-Proxy-Szenarien reicht das Distributionspaket.
sudo apt update && sudo apt upgrade -y
sudo apt install nginx -y
# Version prüfen
nginx -v
Die Ausgabe bestätigt die installierte Version:
nginx version: nginx/1.28.0 (Ubuntu)
Aktivieren Sie den Dienst, damit er nach jedem Neustart automatisch läuft, und prüfen Sie den Status:
sudo systemctl enable --now nginx
sudo systemctl status nginx --no-pager
Sie sollten active (running) sehen. Rufen Sie nun die öffentliche IP Ihres Servers im Browser auf. Die Standard-Willkommensseite von Nginx bestätigt, dass der Server Anfragen auf Port 80 beantwortet. Erscheint nichts, blockiert vermutlich die Firewall den Port, was wir im nächsten Schritt beheben.
Schritt 2: Firewall konfigurieren (UFW)
Die Uncomplicated Firewall (UFW) ist auf Ubuntu vorinstalliert. Öffnen Sie die für einen Reverse Proxy nötigen Ports und sperren Sie alles andere. Nginx registriert beim Setup ein UFW-Profil, das Sie direkt nutzen können.
# SSH erlauben, damit Sie sich nicht aussperren
sudo ufw allow OpenSSH
# HTTP und HTTPS freigeben
sudo ufw allow 'Nginx Full'
# Firewall aktivieren
sudo ufw enable
sudo ufw status verbose
Das Profil Nginx Full öffnet Port 80 und 443 gleichzeitig. Die erwartete Ausgabe:
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW IN Anywhere
Nginx Full ALLOW IN Anywhere
Geben Sie immer zuerst OpenSSH frei, bevor Sie UFW aktivieren. Andernfalls kappt die Firewall Ihre laufende SSH-Sitzung und Sie verlieren den Zugriff auf einen entfernten Server. Wer eine vorgelagerte Hardware- oder Cloud-Firewall einsetzt, sollte dort dieselben Ports freigeben. Für komplexere Netzwerk-Topologien vergleichen wir Firewall-Distributionen im Beitrag zu OPNsense vs pfSense.
Schritt 3: Backend-Anwendung vorbereiten
Der Reverse Proxy braucht einen Dienst, an den er weiterleitet. Zum Testen starten wir eine simple Node.js-Anwendung auf Port 3000, die nur auf localhost lauscht. In der Praxis ersetzen Sie dies durch Ihre echte Anwendung, das Prinzip bleibt identisch: Das Backend bindet sich an 127.0.0.1, nicht an 0.0.0.0.
// app.js
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Hallo vom Backend auf Port 3000\n');
});
// WICHTIG: nur an localhost binden, nicht an 0.0.0.0
server.listen(3000, '127.0.0.1', () => {
console.log('Backend laeuft auf http://127.0.0.1:3000');
});
Starten Sie die Anwendung und prüfen Sie lokal mit curl, dass sie antwortet:
node app.js &
curl http://127.0.0.1:3000
# Ausgabe: Hallo vom Backend auf Port 3000
Indem das Backend ausschließlich auf 127.0.0.1 lauscht, ist es aus dem Internet nicht direkt erreichbar. Selbst wenn ein Angreifer Port 3000 in der Firewall offen findet, bekommt er keine Verbindung, weil der Dienst nur lokale Sockets akzeptiert. Im Produktivbetrieb verwalten Sie den Prozess mit systemd, PM2 oder Docker, damit er nach einem Absturz oder Neustart automatisch wieder hochfährt.
Schritt 4: Grundlegende Reverse-Proxy-Konfiguration
Jetzt erstellen Sie die erste server-Konfiguration. Legen Sie pro Domain eine Datei unter /etc/nginx/sites-available/ an und verlinken Sie sie nach sites-enabled/. Diese Trennung erlaubt es, eine Site zu deaktivieren, ohne ihre Konfiguration zu löschen.
sudo nano /etc/nginx/sites-available/example.conf
Fügen Sie die folgende Konfiguration ein. Ersetzen Sie example.com durch Ihre Domain. Wir definieren einen upstream-Block, damit ein späterer Wechsel auf mehrere Backends nur eine Zeile betrifft.
upstream backend_app {
server 127.0.0.1:3000;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://backend_app;
proxy_http_version 1.1;
# Original-Header an das Backend weitergeben
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 "";
}
}
Die proxy_set_header-Direktiven sind entscheidend. Ohne Host bekommt das Backend einen falschen Hostnamen, ohne X-Forwarded-For sieht es nur die IP des Proxys statt die des echten Clients. Aktivieren Sie die Site, testen Sie die Syntax und laden Sie Nginx neu:
sudo ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Der Befehl nginx -t liefert bei korrekter Syntax:
nginx: configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Rufen Sie nun Ihre Domain über HTTP auf. Statt der Nginx-Willkommensseite erscheint jetzt die Antwort des Backends. Der Reverse Proxy funktioniert, allerdings noch unverschlüsselt. Das ändern wir in den nächsten Schritten.
Schritt 5: DNS und Domain richtig setzen
Damit Let’s Encrypt ein Zertifikat ausstellt, muss Ihre Domain auf die Server-IP zeigen. Legen Sie bei Ihrem DNS-Anbieter einen A-Record (IPv4) und idealerweise einen AAAA-Record (IPv6) an. Prüfen Sie die Auflösung von einem anderen Rechner aus:
dig +short example.com A
dig +short example.com AAAA
# Erwartete Ausgabe: Ihre Server-IP, z. B.
# 203.0.113.10
DNS-Änderungen brauchen je nach TTL Minuten bis Stunden, bis sie weltweit greifen. Warten Sie, bis dig die korrekte IP zurückgibt, bevor Sie Certbot starten. Die HTTP-01-Challenge von Let’s Encrypt schlägt fehl, solange die Validierungsserver Ihre Domain nicht auf den richtigen Host auflösen. Setzen Sie sowohl example.com als auch www.example.com, damit das Zertifikat beide Varianten abdeckt.
Schritt 6: Certbot installieren
Die EFF empfiehlt die Installation von Certbot über snap, weil Sie so immer die aktuelle Version mit allen Plugins erhalten. Entfernen Sie eventuell vorhandene apt-Pakete, um Konflikte zu vermeiden, und installieren Sie das snap.
# Eventuelle alte Pakete entfernen
sudo apt remove certbot -y
# Certbot via snap installieren
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
certbot --version
# Ausgabe: certbot 2.x oder neuer
Certbot spricht das ACME-Protokoll mit den Servern von Let’s Encrypt, der weltweit größten Zertifizierungsstelle. Let’s Encrypt stellt Domain-validierte Zertifikate kostenlos aus und hat damit HTTPS für Millionen Websites zugänglich gemacht. Das nginx-Plugin von Certbot kann Ihre Konfiguration automatisch anpassen, was wir im nächsten Schritt nutzen. Details zur Organisation finden Sie auf der offiziellen Let’s-Encrypt-Seite und zur Installation in der Certbot-Dokumentation.
Schritt 7: HTTPS mit Let’s Encrypt aktivieren
Jetzt stellen Sie das Zertifikat aus und lassen Certbot die HTTPS-Weiterleitung einrichten. Das nginx-Plugin liest Ihre server_name-Einträge, holt das Zertifikat per HTTP-01-Challenge und schreibt die TLS-Direktiven direkt in Ihre Konfiguration.
sudo certbot --nginx -d example.com -d www.example.com
Certbot fragt nach einer E-Mail-Adresse für Ablaufwarnungen und ob HTTP auf HTTPS umgeleitet werden soll. Wählen Sie die Umleitung. Die Erfolgsmeldung sieht so aus:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-09-12.
Deploying certificate
Successfully deployed certificate for example.com
Congratulations! You have successfully enabled HTTPS on https://example.com
Standard-Zertifikate von Let’s Encrypt sind 90 Tage gültig. 2025 führte die Zertifizierungsstelle zusätzlich ein Profil für kurzlebige Zertifikate mit nur sechs Tagen Gültigkeit ein, das die Angriffsfläche kompromittierter Schlüssel weiter verkleinert. Im selben Jahr stellte Let’s Encrypt die OCSP-Unterstützung ein und setzt für Sperrinformationen auf CRLs. Für die meisten Reverse-Proxy-Setups bleiben die regulären 90-Tage-Zertifikate die richtige Wahl, weil sie sich vollautomatisch erneuern lassen (siehe Schritt 12).
Rufen Sie Ihre Domain jetzt mit https:// auf. Das Schloss-Symbol im Browser bestätigt die verschlüsselte Verbindung. Was hinter diesem Symbol steckt, erklären wir ausführlich im Beitrag zu HTTPS und TLS.
Schritt 8: TLS härten (Protokolle und Cipher Suites)
Certbot hinterlegt eine solide Grundkonfiguration, doch für maximale Sicherheit härten Sie TLS manuell. Deaktivieren Sie veraltete Protokolle und beschränken Sie sich auf moderne Cipher Suites. Die folgende Tabelle zeigt, welche Protokolle Sie 2026 aktivieren und welche Sie abschalten sollten.
| Protokoll | Status 2026 | Empfehlung |
|---|---|---|
| TLS 1.3 | Aktueller Standard | Aktivieren (bevorzugt) |
| TLS 1.2 | Weit verbreitet | Aktivieren (Kompatibilität) |
| TLS 1.1 | Veraltet, unsicher | Deaktivieren |
| TLS 1.0 | Veraltet, unsicher | Deaktivieren |
| SSLv3 / SSLv2 | Gebrochen | Deaktivieren |
Erstellen Sie eine wiederverwendbare TLS-Konfiguration, die Sie in jeden HTTPS-Server einbinden. Die Werte orientieren sich am “Intermediate”-Profil des Mozilla SSL Configuration Generators, das einen guten Kompromiss aus Sicherheit und Kompatibilität bietet.
sudo nano /etc/nginx/snippets/tls-hardening.conf
# Nur moderne Protokolle
ssl_protocols TLSv1.2 TLSv1.3;
# TLS 1.2 Cipher Suites (TLS 1.3 nutzt eigene, feste Suites)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# Session-Handling
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# Sichere Kurven
ssl_ecdh_curve X25519:secp384r1;
Binden Sie das Snippet in Ihren HTTPS-Server ein, indem Sie include /etc/nginx/snippets/tls-hardening.conf; in den server-Block schreiben. Nach nginx -t und reload prüfen Sie Ihre Konfiguration mit dem kostenlosen SSL Labs Server Test. Ziel ist die Note A oder A+. Die exakten Cipher-Listen für jedes Profil generiert der Mozilla SSL Configuration Generator passend zu Ihrer Nginx- und OpenSSL-Version.
Schritt 9: HTTP-Sicherheits-Header setzen
Sicherheits-Header weisen den Browser an, wie er mit Ihrer Seite umgehen soll. Sie schützen vor Clickjacking, Protokoll-Downgrades und Cross-Site-Scripting. Das OWASP Secure Headers Project pflegt eine aktuelle Liste der empfohlenen Header. Die folgende Tabelle fasst die wichtigsten zusammen.
| Header | Empfohlener Wert | Schutz vor |
|---|---|---|
| Strict-Transport-Security | max-age=63072000; includeSubDomains | Protokoll-Downgrade, SSL-Stripping |
| X-Frame-Options | SAMEORIGIN | Clickjacking |
| X-Content-Type-Options | nosniff | MIME-Type-Sniffing |
| Content-Security-Policy | default-src ‘self’ | Cross-Site-Scripting (XSS) |
| Referrer-Policy | strict-origin-when-cross-origin | Metadaten-Leaks |
Legen Sie ein zweites Snippet an und binden Sie es ebenfalls in Ihren HTTPS-Server ein:
sudo nano /etc/nginx/snippets/security-headers.conf
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'" always;
# Server-Version verbergen
server_tokens off;
Das Schlüsselwort always sorgt dafür, dass die Header auch bei Fehlerseiten (4xx, 5xx) gesendet werden. Setzen Sie HSTS mit max-age=63072000 (zwei Jahre) erst, wenn HTTPS zuverlässig läuft, denn der Browser merkt sich die Anweisung und verweigert danach unverschlüsselte Verbindungen. Die Content-Security-Policy ist die wirksamste, aber auch komplexeste Direktive. Beginnen Sie restriktiv und erweitern Sie sie gezielt um die Quellen, die Ihre Anwendung wirklich benötigt. Als Referenz dient das OWASP Secure Headers Project.
Schritt 10: Rate-Limiting gegen Brute-Force und DDoS
Rate-Limiting begrenzt, wie viele Anfragen ein Client pro Zeiteinheit stellen darf. Das bremst Brute-Force-Angriffe auf Login-Seiten und mildert einfache DDoS-Versuche. Nginx nutzt dafür limit_req_zone (definiert eine geteilte Speicherzone) und limit_req (wendet das Limit an). Die Zonendefinition gehört in den http-Block in /etc/nginx/nginx.conf.
# In /etc/nginx/nginx.conf, innerhalb von http { ... }
# Allgemeine Zone: 10 Anfragen/Sekunde pro IP
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# Strenge Zone fuer Login-Endpunkte: 1 Anfrage/Sekunde
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
# Maximale gleichzeitige Verbindungen pro IP
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
Wenden Sie die Limits in den passenden location-Blöcken an. Der burst-Parameter erlaubt kurze Lastspitzen, nodelay verarbeitet diese sofort statt verzögert.
location / {
limit_req zone=general burst=20 nodelay;
limit_conn conn_limit 10;
proxy_pass http://backend_app;
}
location /login {
limit_req zone=login burst=5 nodelay;
proxy_pass http://backend_app;
}
Überschreitet ein Client das Limit, antwortet Nginx mit Status 503 (oder 429, wenn Sie limit_req_status 429; setzen). Im Error-Log erscheint dann ein Eintrag wie dieser:
2026/06/14 10:22:41 [error] 8123#8123: *44 limiting requests,
excess: 20.500 by zone "login", client: 198.51.100.23,
server: example.com, request: "POST /login HTTP/2.0"
Wählen Sie die Raten an Ihrem echten Traffic-Muster orientiert. Zu strenge Limits sperren legitime Nutzer aus, zu lockere bieten kaum Schutz. Rate-Limiting ersetzt keine dedizierte Web Application Firewall, ist aber eine wirksame erste Verteidigungslinie direkt im Reverse Proxy.
Schritt 11: HTTP/2 und HTTP/3 (QUIC) aktivieren
HTTP/2 multiplext mehrere Anfragen über eine Verbindung und beschleunigt das Laden spürbar. HTTP/3 setzt auf QUIC über UDP und eliminiert das Head-of-Line-Blocking auf Transportebene. Nginx unterstützt HTTP/3 seit Version 1.25.0 (Mai 2023), in aktuellen stabilen Releases ist es enthalten. HTTP/2 aktivieren Sie mit dem http2-Parameter, HTTP/3 zusätzlich über einen listen-Eintrag auf UDP-Port 443.
server {
# HTTP/2 ueber TCP 443
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
# HTTP/3 ueber UDP 443 (QUIC)
listen 443 quic reuseport;
listen [::]:443 quic reuseport;
server_name example.com www.example.com;
# Browser auf HTTP/3 hinweisen
add_header Alt-Svc 'h3=":443"; ma=86400' always;
}
Geben Sie für HTTP/3 zusätzlich UDP-Port 443 in der Firewall frei: sudo ufw allow 443/udp. Der Alt-Svc-Header signalisiert dem Browser, dass HTTP/3 verfügbar ist. Beim nächsten Besuch wechselt er automatisch auf QUIC. Verwenden Sie reuseport nur einmal pro Adresse und Port, sonst lehnt Nginx den Start ab.
Schritt 12: Automatische Zertifikatserneuerung einrichten
Let’s-Encrypt-Zertifikate laufen nach 90 Tagen ab. Certbot installiert beim Setup einen systemd-Timer, der zweimal täglich prüft, ob eine Erneuerung fällig ist, und sie bei Bedarf durchführt. Testen Sie diesen Mechanismus mit einem Trockenlauf, bevor Sie sich darauf verlassen.
# Erneuerung simulieren, ohne ein echtes Zertifikat anzufordern
sudo certbot renew --dry-run
# Timer-Status pruefen
sudo systemctl list-timers | grep certbot
Der Trockenlauf endet mit einer Erfolgsmeldung pro Zertifikat:
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
Damit Nginx das erneuerte Zertifikat lädt, muss der Dienst nach der Erneuerung neu geladen werden. Certbot erledigt das über einen Deploy-Hook. Setzen Sie ihn global, damit jede Erneuerung Nginx automatisch neu lädt:
# Deploy-Hook fuer alle Erneuerungen setzen
sudo sh -c 'echo "deploy_hook = systemctl reload nginx" >> /etc/letsencrypt/cli.ini'
# Mit Hook testen
sudo certbot renew --deploy-hook "systemctl reload nginx" --dry-run
Ab jetzt erneuert sich Ihr Zertifikat vollautomatisch und Nginx übernimmt es ohne manuelles Eingreifen. Damit ist der Reverse Proxy produktionsreif: verschlüsselt, automatisch wartbar und gegen die häufigsten Angriffe gehärtet.
Komplettes Konfigurationsbeispiel
Hier ist die vollständige, produktionsreife Konfiguration, die alle vorherigen Schritte zusammenführt. Sie leitet HTTP auf HTTPS um, terminiert TLS, setzt Sicherheits-Header, limitiert Anfragen und unterstützt HTTP/2 sowie HTTP/3.
upstream backend_app {
server 127.0.0.1:3000;
keepalive 32;
}
# HTTP: alles auf HTTPS umleiten
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# HTTPS: Reverse Proxy mit TLS, Headern und Rate-Limiting
server {
listen 443 ssl;
listen [::]:443 ssl;
listen 443 quic reuseport;
listen [::]:443 quic reuseport;
http2 on;
server_name example.com www.example.com;
# Zertifikate von Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Wiederverwendbare Snippets
include /etc/nginx/snippets/tls-hardening.conf;
include /etc/nginx/snippets/security-headers.conf;
add_header Alt-Svc 'h3=":443"; ma=86400' always;
location / {
limit_req zone=general burst=20 nodelay;
limit_conn conn_limit 10;
proxy_pass http://backend_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 "";
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
}
location /login {
limit_req zone=login burst=5 nodelay;
proxy_pass http://backend_app;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Speichern Sie die Datei, testen Sie mit sudo nginx -t und laden Sie mit sudo systemctl reload nginx neu. Diese Konfiguration ist ein solider Ausgangspunkt für die meisten Webanwendungen und lässt sich modular um weitere location-Blöcke oder zusätzliche Domains erweitern.
WebSockets und mehrere Backends weiterleiten
WebSocket-Verbindungen korrekt durchreichen
Anwendungen mit Echtzeit-Funktionen (Chats, Live-Dashboards) nutzen WebSockets. Diese benötigen das HTTP-Upgrade-Protokoll, das Sie explizit durchreichen müssen. Ohne die folgenden Header bricht die Verbindung sofort ab.
location /ws/ {
proxy_pass http://backend_app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
}
Last auf mehrere Instanzen verteilen
Skaliert Ihre Anwendung über mehrere Prozesse oder Server, erweitern Sie den upstream-Block. Nginx verteilt die Last und nimmt ausgefallene Knoten automatisch aus der Rotation.
upstream backend_app {
least_conn;
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
server 10.0.0.5:3000 backup;
keepalive 32;
}
Die Direktive least_conn schickt neue Anfragen an die Instanz mit den wenigsten aktiven Verbindungen. Der mit backup markierte Server springt nur ein, wenn alle primären Knoten ausfallen. So erreichen Sie Hochverfügbarkeit ohne externen Load Balancer.
Fünf häufige Fehler und wie Sie sie vermeiden
1. Fehlender Host-Header. Ohne proxy_set_header Host $host; sendet Nginx den Upstream-Namen statt der echten Domain. Anwendungen mit virtuellen Hosts oder absoluten Redirects liefern dann falsche URLs aus oder zeigen die falsche Seite. Setzen Sie den Host-Header in jedem location-Block, der weiterleitet.
2. Backend bindet an 0.0.0.0. Lauscht Ihre Anwendung auf allen Interfaces statt nur auf 127.0.0.1, ist sie unter Umständen direkt aus dem Internet erreichbar und umgeht den Reverse Proxy komplett. Binden Sie Backends immer an localhost und verlassen Sie sich nicht allein auf die Firewall.
3. HSTS zu früh aktiviert. Wer Strict-Transport-Security mit langer max-age setzt, bevor HTTPS stabil läuft, sperrt Besucher aus. Der Browser merkt sich die Anweisung und verweigert HTTP, selbst wenn HTTPS später Probleme macht. Testen Sie HTTPS gründlich, bevor Sie HSTS scharf schalten, und beginnen Sie mit kurzer Laufzeit.
4. Vergessenes nginx -t. Ein systemctl reload mit fehlerhafter Konfiguration kann Nginx in einen inkonsistenten Zustand bringen. Prüfen Sie jede Änderung erst mit nginx -t. Der Test findet Syntaxfehler, bevor sie produktiv werden.
5. Zertifikatserneuerung ohne Reload. Erneuert Certbot das Zertifikat, lädt Nginx es nicht automatisch. Ohne Deploy-Hook serviert der Server bis zum nächsten Neustart das alte Zertifikat weiter, das eventuell schon abgelaufen ist. Konfigurieren Sie den Reload-Hook wie in Schritt 12 beschrieben.
Troubleshooting: Die häufigsten Probleme lösen
Treten Probleme auf, liefert das Error-Log die entscheidenden Hinweise. Verfolgen Sie es live mit sudo tail -f /var/log/nginx/error.log. Die folgende Tabelle ordnet typische Symptome ihren Ursachen und Lösungen zu.
| Symptom | Ursache | Lösung |
|---|---|---|
| 502 Bad Gateway | Backend nicht erreichbar oder abgestürzt | Backend-Prozess prüfen, Port und proxy_pass abgleichen |
| 504 Gateway Timeout | Backend antwortet zu langsam | proxy_read_timeout erhöhen, Backend-Performance prüfen |
| connection refused (upstream) | Backend lauscht auf anderem Port | Port im upstream-Block korrigieren |
| SSL-Handshake schlägt fehl | Falscher Zertifikatspfad oder abgelaufen | Pfade prüfen, certbot renew ausführen |
| Certbot-Challenge schlägt fehl | DNS zeigt nicht auf Server oder Port 80 zu | dig prüfen, UFW Port 80 freigeben |
| Header erscheinen doppelt | add_header auf mehreren Ebenen | Header nur auf einer Ebene setzen |
| WebSocket bricht ab | Upgrade-Header fehlt | Upgrade- und Connection-Header setzen |
| Echte Client-IP fehlt im Log | X-Forwarded-For nicht ausgewertet | real_ip_module oder Backend-Auswertung konfigurieren |
Der Fehler 502 Bad Gateway ist mit Abstand der häufigste. Er bedeutet fast immer, dass das Backend nicht läuft oder Nginx es unter der konfigurierten Adresse nicht findet. Prüfen Sie mit curl http://127.0.0.1:3000, ob das Backend lokal antwortet, und vergleichen Sie den Port mit Ihrem upstream-Block. Bei TLS-Problemen liefert openssl s_client -connect example.com:443 -servername example.com die Details des Handshakes und des präsentierten Zertifikats.
Fortgeschrittene Tipps für den Produktivbetrieb
Gzip und Brotli für kleinere Antworten. Komprimieren Sie Textantworten, um Bandbreite zu sparen und Ladezeiten zu senken. Gzip ist überall verfügbar, Brotli komprimiert noch stärker, benötigt aber das passende Modul.
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml;
Proxy-Caching für statische Antworten. Cachen Sie Backend-Antworten, die sich selten ändern, direkt im Proxy. Das entlastet das Backend drastisch und beschleunigt wiederholte Abrufe.
# Im http-Block
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app_cache:10m max_size=1g inactive=60m;
# Im location-Block
proxy_cache app_cache;
proxy_cache_valid 200 10m;
add_header X-Cache-Status $upstream_cache_status;
Echte Client-IP korrekt protokollieren. Hinter einem weiteren Proxy oder CDN (etwa Cloudflare) müssen Sie Nginx mitteilen, welchen Quell-IPs es vertrauen darf, damit X-Forwarded-For nicht gefälscht werden kann. Konfigurieren Sie set_real_ip_from mit den vertrauenswürdigen Netzbereichen und real_ip_header X-Forwarded-For;.
Logging und Monitoring. Aktivieren Sie das Access-Log im JSON-Format für maschinelle Auswertung und überwachen Sie 4xx- und 5xx-Raten. Ein plötzlicher Anstieg von 502-Fehlern weist auf ein abgestürztes Backend hin, eine Welle von 429 oder 503 auf einen laufenden Brute-Force-Angriff, den Ihr Rate-Limiting abfängt. Für ganzheitliche Server-Absicherung lohnt sich der Blick in unseren Überblick zur Online-Sicherheit.
Nginx-Sicherheitslücken 2025 und 2026 im Blick
Ein Reverse Proxy ist die exponierteste Komponente Ihrer Architektur, deshalb gehören Updates zur Pflicht. 2025 und 2026 wurden mehrere sicherheitsrelevante Fehler in Nginx behoben. Anfang 2025 etwa schloss das Projekt mit CVE-2025-23419 eine Schwachstelle bei der Wiederverwendung von TLS-Sitzungen, die in nginx 1.27.4 behoben wurde. Im Verlauf von 2025 und 2026 folgten weitere Fixes in den Bereichen TLS-Sitzungsbehandlung, HTTP/2- und HTTP/3-Verarbeitung sowie bei OCSP-Anfragen über den Resolver.
Die praktische Konsequenz ist einfach: Halten Sie Nginx aktuell, abonnieren Sie die Sicherheitsmeldungen des Projekts und spielen Sie Updates zeitnah ein. Auf Ubuntu liefern die Standard-Repositories Sicherheitspatches für den stabilen Zweig, mit unattended-upgrades automatisieren Sie das Einspielen. Reverse Proxies und Load Balancer sind ein beliebtes Angriffsziel, wie auch die schwere Citrix-NetScaler-Lücke 2026 gezeigt hat. Wer seine Konfiguration regelmäßig gegen den SSL Labs Test und das OWASP Secure Headers Project prüft, schließt die häufigsten Fehlerquellen aus. Die maßgebliche Referenz für alle Direktiven bleibt die offizielle Nginx-HTTPS-Dokumentation.
Fazit: Ihr gehärteter Reverse Proxy
Sie haben in zwölf Schritten einen vollwertigen Nginx Reverse Proxy aufgebaut: von der Installation über die Backend-Anbindung, TLS-Terminierung mit Let’s Encrypt, gehärtete Cipher Suites, Sicherheits-Header und Rate-Limiting bis zur automatischen Zertifikatserneuerung. Diese Konfiguration ist produktionsreif und folgt den Sicherheitsempfehlungen für 2026.
Der nächste sinnvolle Schritt ist Monitoring: Behalten Sie Fehlerraten, Zertifikatslaufzeiten und Antwortzeiten im Auge. Erweitern Sie die Konfiguration modular, wenn neue Dienste hinzukommen, und prüfen Sie Ihre TLS-Konfiguration regelmäßig gegen aktuelle Empfehlungen. Ein gut gewarteter Reverse Proxy ist über Jahre die verlässliche Eingangstür zu Ihrer gesamten Infrastruktur.
Häufig gestellte Fragen (FAQ)
Was ist der Unterschied zwischen einem Reverse Proxy und einem Load Balancer?
Ein Reverse Proxy nimmt Anfragen entgegen und leitet sie an ein oder mehrere Backends weiter. Ein Load Balancer ist eine Spezialform, die Last gezielt auf mehrere Server verteilt. Nginx erfüllt beide Rollen: Mit einem einzelnen Backend ist es ein reiner Reverse Proxy, mit mehreren server-Einträgen im upstream-Block wird es zum Load Balancer.
Brauche ich Nginx oder reicht Caddy oder Traefik?
Caddy und Traefik holen Zertifikate automatisch und sind schneller eingerichtet. Nginx bietet dafür mehr Kontrolle, höhere Performance unter Last und eine riesige Wissensbasis. Für klassische Server-Setups und maximale Flexibilität ist Nginx weiterhin der Standard, für containerlastige Umgebungen kann Traefik bequemer sein.
Wie oft erneuert sich das Let’s-Encrypt-Zertifikat?
Standard-Zertifikate sind 90 Tage gültig. Der von Certbot installierte systemd-Timer prüft zweimal täglich und erneuert automatisch, sobald weniger als 30 Tage Restlaufzeit verbleiben. Mit korrekt gesetztem Deploy-Hook lädt Nginx das neue Zertifikat ohne manuelles Eingreifen.
Warum bekomme ich einen 502 Bad Gateway?
Der häufigste Grund ist ein nicht laufendes Backend. Prüfen Sie mit curl http://127.0.0.1:3000, ob Ihr Dienst antwortet, und vergleichen Sie den Port mit dem upstream-Block. Auch ein abgestürzter Anwendungsprozess oder ein falscher proxy_pass-Eintrag lösen diesen Fehler aus.
Sollte ich HTTP/3 sofort aktivieren?
HTTP/3 bringt spürbare Vorteile bei instabilen Verbindungen und mobilen Clients. Da es UDP-Port 443 benötigt und in manchen Netzwerken gefiltert wird, sollten Sie HTTP/2 stets parallel aktiv lassen. So fällt der Browser bei Bedarf zurück. Für die meisten Setups ist die Aktivierung beider Protokolle die beste Wahl.
Wie sichere ich den Reverse Proxy zusätzlich ab?
Kombinieren Sie die Maßnahmen aus dieser Anleitung mit fail2ban gegen wiederholte Angriffe, einer Web Application Firewall wie ModSecurity und regelmäßigen Updates. Beschränken Sie Admin-Bereiche per IP-Allowlist und nutzen Sie für den Serverzugang ausschließlich SSH-Schlüssel statt Passwörter.
Funktioniert diese Anleitung auch auf Debian?
Ja. Die Befehle sind nahezu identisch, da Ubuntu auf Debian basiert. Lediglich die Paketversionen können abweichen. UFW, Nginx und Certbot funktionieren auf aktuellen Debian-Releases genauso. Auf Rocky Linux oder AlmaLinux ersetzen Sie apt durch dnf und beachten die SELinux-Richtlinien.




