Nginx als Reverse Proxy: HTTPS in 20 Minuten
Statt interne Apps direkt freizugeben: Ein sauberes Gateway-Setup mit Nginx und Let's Encrypt. TLS-Verschlüsselung, lokales Port-Mapping und sicheres Routing an einem zentralen Einstiegspunkt.
- Nginx
- Reverse Proxy
- SSL
- Linux
- Webserver
TL;DR
Ein Reverse Proxy wie Nginx nimmt Anfragen von außen entgegen und leitet sie intern an deine eigentliche App weiter. Dadurch brauchst du keine offenen App-Ports nach außen, kannst HTTPS zentral terminieren und mehrere Services sauber unter Domains oder Subdomains betreiben.
Warum ich zu Nginx gewechselt bin
Ich hatte eine Node.js-App auf Port 3000 laufen. Zugriff nur via http://example.com:3000 – unprofessionell.
Ich wollte:
- ✅ Zugriff via
https://example.com(ohne Port) - ✅ SSL/TLS-Verschlüsselung (das grüne Schloss im Browser)
- ✅ Mehrere Apps auf einem Server
Lösung: Nginx als Reverse Proxy.
Was ist ein Reverse Proxy?
Die kurze Antwort: Ein Reverse Proxy nimmt Anfragen entgegen und leitet sie an die richtige App weiter.
Die Analogie: Stell dir Nginx als Empfangschef in einem Hotel vor:
- Gast (Browser) kommt und sagt: “Ich möchte zu Zimmer app1.de”
- Empfangschef (Nginx) prüft die Liste und sagt: “Das ist Port 3000, ich leite weiter”
- Zimmer (Backend-App) antwortet
Ohne Reverse Proxy: Jede App braucht einen eigenen Port und ist direkt erreichbar.
Mit Reverse Proxy: Nginx ist der einzige Einstiegspunkt. Er verteilt Anfragen intern.
Was du brauchst
- Linux-Server (Ubuntu, Debian, oder ähnlich)
- Root-Zugriff (sudo)
- Domain (z.B.
example.com) - Backend-App (z.B. Node.js auf Port 3000)
- 20 Minuten Zeit
Schritt 1: Nginx installieren
# Update
sudo apt update
# Nginx installieren
sudo apt install nginx -y
# Prüfen ob läuft
sudo systemctl status nginx
Testen:
Öffne deinen Browser: http://deine-server-ip
Du solltest die “Welcome to nginx!” Seite sehen.
Schritt 2: Nginx-Config verstehen
Wichtige Verzeichnisse
# Haupt-Config
/etc/nginx/nginx.conf
# Site-Configs (verfügbare Sites)
/etc/nginx/sites-available/
# Aktivierte Sites (Symlinks)
/etc/nginx/sites-enabled/
# Logs
/var/log/nginx/access.log
/var/log/nginx/error.log
Standard-Config deaktivieren
# Standard-Site deaktivieren
sudo rm /etc/nginx/sites-enabled/default
Schritt 3: Reverse Proxy Config erstellen
Szenario
Du hast eine Node.js-App auf Port 3000. Domain: app.example.com
Config-Datei erstellen
sudo nano /etc/nginx/sites-available/app.example.com
Basic Reverse Proxy Config
server {
listen 80;
listen [::]:80;
server_name app.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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;
}
}
Was passiert hier?
listen 80– Nginx hört auf Port 80 (HTTP)server_name– Nur Anfragen für diese Domain werden bearbeitetproxy_pass– Anfragen werden anlocalhost:3000weitergeleitetproxy_set_header– Header werden korrekt weitergegeben
Config aktivieren
# Symlink erstellen
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
# Config testen
sudo nginx -t
# Nginx neu laden
sudo systemctl reload nginx
Testen:
Öffne http://app.example.com – du solltest deine App sehen.
Schritt 4: SSL/TLS mit Let’s Encrypt
Certbot installieren
sudo apt install certbot python3-certbot-nginx -y
Zertifikat erstellen
sudo certbot --nginx -d app.example.com
Was passiert:
- Certbot prüft, ob die Domain auf deinen Server zeigt
- Erstellt SSL-Zertifikat
- Passt Nginx-Config automatisch an
- Richtet Auto-Renewal ein
Fragen während der Installation:
- Email: Deine Email (für Ablauf-Warnungen)
- Terms: Akzeptieren (ja)
- Redirect HTTP → HTTPS: Ja (empfohlen)
Ergebnis: Deine Config wird automatisch erweitert:
server {
server_name app.example.com;
location / {
proxy_pass http://localhost:3000;
# ... proxy headers ...
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = app.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name app.example.com;
return 404; # managed by Certbot
}
Testen:
Öffne https://app.example.com – grünes Schloss im Browser!
Schritt 5: Mehrere Apps einrichten
Szenario
app1.example.com→ Port 3000app2.example.com→ Port 4000api.example.com→ Port 5000
Config für app2
sudo nano /etc/nginx/sites-available/app2.example.com
server {
listen 80;
listen [::]:80;
server_name app2.example.com;
location / {
proxy_pass http://localhost:4000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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;
}
}
# Aktivieren
sudo ln -s /etc/nginx/sites-available/app2.example.com /etc/nginx/sites-enabled/
# SSL hinzufügen
sudo certbot --nginx -d app2.example.com
# Nginx neu laden
sudo systemctl reload nginx
Wiederholen für alle weiteren Apps.
Häufige Fehler (die ich gemacht habe)
Fehler 1: “502 Bad Gateway”
Ursache: Die Backend-App auf Port 3000 läuft nicht.
Lösung:
# Prüfen ob App läuft
curl http://localhost:3000
# Falls nicht: App starten
# Für Node.js:
node app.js
# Oder mit PM2 (empfohlen):
pm2 start app.js
pm2 save
pm2 startup
Fehler 2: DNS zeigt nicht auf Server
Ursache: Domain ist nicht korrekt konfiguriert.
Lösung:
# Prüfen ob Domain auf Server zeigt
dig app.example.com
# Oder:
nslookup app.example.com
DNS-Record sollte deine Server-IP anzeigen.
Wo konfigurieren: Bei deinem Domain-Provider (z.B. Namecheap, Cloudflare):
A-Record: app.example.com → 203.0.113.10
Fehler 3: Certbot schlägt fehl
Ursache: Domain zeigt nicht auf Server oder Port 80 ist blockiert.
Lösung:
# Prüfen ob Port 80 offen ist
sudo netstat -tuln | grep :80
# Firewall-Regel hinzufügen (falls nötig)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Fehler 4: Nginx startet nicht
Ursache: Syntax-Fehler in Config.
Lösung:
# Config testen
sudo nginx -t
# Fehler anzeigen
sudo journalctl -xeu nginx
Nützliche Nginx-Befehle
| Befehl | Was es macht |
|---|---|
sudo systemctl start nginx | Nginx starten |
sudo systemctl stop nginx | Nginx stoppen |
sudo systemctl restart nginx | Nginx neu starten |
sudo systemctl reload nginx | Config neu laden (ohne Neustart) |
sudo systemctl status nginx | Status anzeigen |
sudo nginx -t | Config testen (vor Reload!) |
sudo tail -f /var/log/nginx/error.log | Error-Log live anzeigen |
sudo tail -f /var/log/nginx/access.log | Access-Log live anzeigen |
Erweiterte Config-Optionen
Rate Limiting (DDoS-Schutz)
# In /etc/nginx/nginx.conf im http-Block
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
# In deiner Site-Config
server {
location / {
limit_req zone=mylimit burst=20;
proxy_pass http://localhost:3000;
# ... rest ...
}
}
Was passiert: Maximal 10 Requests pro Sekunde pro IP. Burst erlaubt kurze Spitzen.
Gzip-Kompression aktivieren
# In /etc/nginx/nginx.conf
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss;
Effekt: Responses werden komprimiert → schnellere Ladezeiten.
Client Max Body Size (für File-Uploads)
server {
# Erlaube Uploads bis 100MB
client_max_body_size 100M;
location / {
proxy_pass http://localhost:3000;
# ...
}
}
WebSocket-Support
Bereits in der Basic-Config enthalten via:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
Falls nicht: Ergänzen für Socket.io, WebSockets, etc.
SSL-Zertifikat erneuern
Let’s Encrypt-Zertifikate laufen nach 90 Tagen ab.
Auto-Renewal prüfen:
# Certbot erstellt automatisch einen Cronjob
sudo certbot renew --dry-run
Manuell erneuern:
sudo certbot renew
sudo systemctl reload nginx
Cronjob prüfen:
sudo crontab -l
# Sollte etwas wie:
# 0 */12 * * * certbot renew --quiet
Performance-Tipps
1. HTTP/2 aktivieren
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
# ... rest ...
}
Reload:
sudo systemctl reload nginx
2. Caching aktivieren
# In http-Block in nginx.conf
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;
# In Site-Config
location / {
proxy_cache my_cache;
proxy_cache_valid 200 60m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_pass http://localhost:3000;
# ...
}
3. Keep-Alive erhöhen
# In nginx.conf
keepalive_timeout 65;
keepalive_requests 100;
Monitoring & Logs
Access-Log analysieren
# Top 10 IPs nach Requests
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
# Status-Codes zählen
sudo awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
Error-Log durchsuchen
# Nur Errors
sudo grep "error" /var/log/nginx/error.log
# Letzte 50 Zeilen
sudo tail -50 /var/log/nginx/error.log
Sicherheits-Tipps
1. Security-Header setzen
server {
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self';" always;
location / {
# ...
}
}
2. Server-Token verstecken
# In nginx.conf im http-Block
server_tokens off;
Effekt: Nginx-Version wird nicht mehr in Responses angezeigt.
3. IP-Whitelisting (optional)
location /admin {
allow 192.168.1.0/24; # Nur lokales Netz
deny all;
proxy_pass http://localhost:3000;
}
Fazit
Nginx als Reverse Proxy hat meine Server-Verwaltung vereinfacht.
Vorher: Jede App auf eigenem Port, kein SSL, unprofessionell.
Nachher:
- ✅ Alle Apps via HTTPS erreichbar
- ✅ Ein zentraler Einstiegspunkt
- ✅ Let’s Encrypt SSL automatisch
- ✅ Performance-Optimierungen möglich
Zeitaufwand: 20-30 Minuten (erste App) Schwierigkeitsgrad: Anfänger-Mittel Lohnt sich? Definitiv. Standard für Production.
Mein Tipp: Fang mit einer App an. Wenn das läuft, weitere hinzufügen.
Bei Fragen: schneider@alexle135.de
Quellen:
- Nginx Official Docs
- Let’s Encrypt Certbot
- DigitalOcean Nginx Tutorials
- Eigene Praxiserfahrung (10 Monate Nginx)
FAQ
Häufige Fragen
- Warum ändert ein Slash am Ende von proxy_pass alles?
- Nginx verhält sich unterschiedlich, je nachdem ob die proxy_pass-URL auf einen Slash endet. Mit Slash (proxy_pass http://backend/) ersetzt Nginx den location-Match und hängt den Rest-Path an. Ohne Slash (proxy_pass http://backend) bleibt der komplette Request-Pfad inklusive location-Präfix erhalten. Für eine reine Weiterleitung an ein einzelnes Backend willst du meistens die Variante ohne Slash, also proxy_pass http://localhost:3000;.
- Wofür ist proxy_set_header Host $host; gut?
- Ohne den Header schickt Nginx localhost:3000 als Host-Header ans Backend. Die App sieht also nicht die Domain, unter der der Browser reingekommen ist. Das bricht Redirect-Logik, Multi-Domain-Setups und Cookies. Mit proxy_set_header Host $host; bekommt das Backend die Original-Domain. X-Forwarded-For und X-Real-IP gehören üblicherweise dazu, damit im Backend-Log nicht alle Requests von 127.0.0.1 kommen.
- Wie läuft die Zertifikats-Erneuerung mit Certbot?
- Certbot installiert je nach Distribution einen systemd-Timer (certbot.timer) oder einen Cron-Job unter /etc/cron.d/certbot. Der ruft zweimal täglich certbot renew auf. Lets-Encrypt-Zertifikate sind 90 Tage gültig, Certbot erneuert ab 30 Tagen Restlaufzeit. Prüfung mit systemctl list-timers | grep certbot oder manuell per certbot renew --dry-run. Logs landen unter /var/log/letsencrypt/letsencrypt.log.
Weiterlesen
Ähnliche Artikel
Traefik v3 hinter Docker: HTTPS, WebContainer-Header und Auto-Rollback in der Praxis
Wie ich alexle135.de mit Traefik v3, Let's Encrypt, Astro SSR und getrennten CSP-Middlewares für die WebContainer-Terminal-Missionen produktiv betreibe – inklusive Auto-Rollback über den Healthgate-Smoke.
Pangolin statt Cloudflare Tunnel: den eigenen Ingress-Pfad zurückholen
Cloudflare Tunnel ist bequem, aber dein Traffic läuft komplett über fremde Infrastruktur. Pangolin macht deinen eigenen VPS zum Eingangstor. Hier der komplette Aufbau mit Installer, Traefik und dem Newt-Connector.
Das Terminal 2026: atuin, zoxide, yazi, lazygit und uv im Alltag
Die Rust-Generation der CLI-Tools ist über bat und exa hinaus. Sechs Werkzeuge, die ich täglich nutze, mit den Shell-Init-Zeilen, die du wirklich brauchst, und ohne die übliche Listicle-Beliebigkeit.