Webapplikationen, APIs und Dashboards laufen intern auf verschiedenen Ports und Servern. Sie direkt ins Internet zu stellen ist ein Sicherheitsrisiko — offene Ports, fehlende TLS-Verschlüsselung und keine zentrale Zugriffskontrolle. Ein Nginx Reverse Proxy löst diese Probleme: Er bündelt alle Dienste hinter einem einzigen Einstiegspunkt, terminiert TLS, setzt Security Headers und limitiert Zugriffe.
Was ist ein Reverse Proxy?
Ein Reverse Proxy nimmt eingehende Client-Anfragen entgegen und leitet sie an interne Backend-Server weiter. Der Client kommuniziert nur mit dem Proxy — die Backend-Server sind nicht direkt erreichbar.
Internet → Nginx (Port 443) → Backend 1 (10.0.20.10:3000)
→ Backend 2 (10.0.20.11:8080)
→ Backend 3 (10.0.20.12:9090)
Vorteile
- TLS-Terminierung: Ein Zertifikat für alle Dienste, zentral verwaltet
- Zentrale Zugriffskontrolle: Rate Limiting, IP-Filtering, Basic Auth
- Security Headers: HSTS, CSP, X-Frame-Options an einer Stelle konfigurieren
- Load Balancing: Traffic auf mehrere Backend-Server verteilen
- Caching: Statische Inhalte cachen, Backend entlasten
- Logging: Zentrale Access- und Error-Logs
Nginx installieren und konfigurieren
Installation
# Debian/Ubuntu
apt update && apt install nginx -y
# Nginx starten und aktivieren
systemctl enable --now nginx
# Statusprüfung
systemctl status nginx
Grundstruktur der Konfiguration
Nginx nutzt eine hierarchische Konfiguration:
/etc/nginx/
├── nginx.conf # Hauptkonfiguration
├── sites-available/ # Verfügbare Server Blocks
│ ├── default
│ ├── grafana.example.com
│ └── nextcloud.example.com
├── sites-enabled/ # Aktive Server Blocks (Symlinks)
│ ├── grafana.example.com -> ../sites-available/grafana.example.com
│ └── nextcloud.example.com -> ../sites-available/nextcloud.example.com
├── snippets/ # Wiederverwendbare Konfigurationsblöcke
│ ├── ssl-params.conf
│ ├── security-headers.conf
│ └── proxy-params.conf
└── conf.d/ # Zusätzliche Konfigurationen
Globale Nginx-Optimierung
In /etc/nginx/nginx.conf die Grundeinstellungen optimieren:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
# Grundeinstellungen
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off; # Nginx-Version nicht preisgeben
# Logging
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$upstream_response_time';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
# Gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Server Blocks und proxy_pass
Einfacher Reverse Proxy
Beispiel: Grafana (intern auf Port 3000) über grafana.example.com erreichbar machen:
# /etc/nginx/sites-available/grafana.example.com
server {
listen 80;
server_name grafana.example.com;
# HTTP → HTTPS Redirect
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name grafana.example.com;
ssl_certificate /etc/letsencrypt/live/grafana.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/grafana.example.com/privkey.pem;
include snippets/ssl-params.conf;
include snippets/security-headers.conf;
location / {
proxy_pass http://10.0.20.10:3000;
include snippets/proxy-params.conf;
}
}
Aktivieren:
ln -s /etc/nginx/sites-available/grafana.example.com /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Proxy-Parameter als Snippet
Erstellen Sie /etc/nginx/snippets/proxy-params.conf für wiederverwendbare Proxy-Einstellungen:
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 X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
Die Header sind entscheidend:
- X-Real-IP: Die tatsächliche Client-IP (nicht die Proxy-IP)
- X-Forwarded-For: Kette aller Proxies im Pfad
- X-Forwarded-Proto: Ob der Client HTTPS oder HTTP verwendet
- Host: Der ursprüngliche Hostname der Anfrage
Ohne diese Header sieht das Backend nur die IP des Nginx-Servers und weiß nicht, ob der Client TLS verwendet.
SSL-Terminierung mit Let’s Encrypt
Certbot installieren
apt install certbot python3-certbot-nginx -y
Zertifikat beantragen
# Automatisch mit Nginx-Plugin
certbot --nginx -d grafana.example.com
# Oder manuell (Standalone)
certbot certonly --standalone -d grafana.example.com
# Wildcard-Zertifikat (DNS-Challenge)
certbot certonly --manual --preferred-challenges dns -d '*.example.com'
SSL-Parameter als Snippet
Erstellen Sie /etc/nginx/snippets/ssl-params.conf:
# Moderne TLS-Konfiguration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# SSL-Session-Cache
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 9.9.9.9 valid=300s;
# DH-Parameter (einmalig generieren: openssl dhparam -out /etc/nginx/dhparam.pem 4096)
ssl_dhparam /etc/nginx/dhparam.pem;
Automatische Erneuerung
# Certbot-Timer prüfen
systemctl status certbot.timer
# Manueller Test der Erneuerung
certbot renew --dry-run
Certbot erneuert Zertifikate automatisch 30 Tage vor Ablauf und lädt Nginx per Post-Hook neu:
# /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
WebSocket-Support
Viele moderne Applikationen nutzen WebSockets (Grafana, Proxmox Console, Nextcloud Talk). WebSockets erfordern spezielle Proxy-Konfiguration:
# /etc/nginx/sites-available/proxmox.example.com
server {
listen 443 ssl http2;
server_name proxmox.example.com;
ssl_certificate /etc/letsencrypt/live/proxmox.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/proxmox.example.com/privkey.pem;
include snippets/ssl-params.conf;
location / {
proxy_pass https://10.0.20.5:8006;
include snippets/proxy-params.conf;
# WebSocket-Support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Längere Timeouts für VNC/Console
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Die zwei entscheidenden Zeilen für WebSockets sind:
proxy_set_header Upgrade $http_upgrade;— signalisiert dem Backend das Protokoll-Upgradeproxy_set_header Connection "upgrade";— hält die Verbindung für WebSocket offen
Rate Limiting
Rate Limiting schützt vor Brute-Force-Angriffen, DDoS und übermäßiger API-Nutzung.
Rate-Limit-Zone definieren
In /etc/nginx/nginx.conf (im http-Block):
# 10 Requests/Sekunde pro IP, 10 MB Speicher für Tracking
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# Strengeres Limit für Login-Seiten
limit_req_zone $binary_remote_addr zone=login:10m rate=3r/s;
# API-Limit
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
Rate Limiting anwenden
server {
listen 443 ssl http2;
server_name app.example.com;
# Allgemeines Rate Limiting
location / {
limit_req zone=general burst=20 nodelay;
proxy_pass http://10.0.20.15:8080;
include snippets/proxy-params.conf;
}
# Strenges Limit für Login
location /login {
limit_req zone=login burst=5 nodelay;
proxy_pass http://10.0.20.15:8080;
include snippets/proxy-params.conf;
}
# API mit eigenem Limit
location /api/ {
limit_req zone=api burst=50 nodelay;
proxy_pass http://10.0.20.15:8080;
include snippets/proxy-params.conf;
}
}
Parameter:
- rate=10r/s: Maximale Anfragen pro Sekunde
- burst=20: Erlaubt kurzzeitig 20 zusätzliche Anfragen (werden verzögert abgearbeitet)
- nodelay: Burst-Anfragen sofort verarbeiten statt verzögern
Security Headers
Erstellen Sie /etc/nginx/snippets/security-headers.conf:
# HSTS: Browser soll nur HTTPS verwenden (2 Jahre)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Clickjacking-Schutz
add_header X-Frame-Options "SAMEORIGIN" always;
# XSS-Schutz
add_header X-Content-Type-Options "nosniff" always;
# Referrer-Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions-Policy
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# Content-Security-Policy (anpassen je nach Applikation)
# add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;
Die Content-Security-Policy ist auskommentiert, da sie für jede Applikation individuell angepasst werden muss. Eine zu restriktive CSP kann die Funktionalität der Webapp beeinträchtigen.
Headers testen
# Header-Check mit curl
curl -I https://grafana.example.com
# Oder online: securityheaders.com
Mehrere Dienste auf einem Server
Ein typisches Setup mit mehreren internen Diensten:
# Grafana
server {
listen 443 ssl http2;
server_name grafana.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include snippets/ssl-params.conf;
include snippets/security-headers.conf;
location / {
proxy_pass http://10.0.20.10:3000;
include snippets/proxy-params.conf;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Nextcloud
server {
listen 443 ssl http2;
server_name cloud.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include snippets/ssl-params.conf;
include snippets/security-headers.conf;
client_max_body_size 10G; # Große Uploads erlauben
location / {
proxy_pass http://10.0.20.11:80;
include snippets/proxy-params.conf;
}
}
# Proxmox VE
server {
listen 443 ssl http2;
server_name pve.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include snippets/ssl-params.conf;
location / {
proxy_pass https://10.0.20.5:8006;
include snippets/proxy-params.conf;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
}
Mit einem Wildcard-Zertifikat (*.example.com) reicht ein einzelnes Zertifikat für alle Subdomains.
Troubleshooting
Häufige Fehler
| Symptom | Ursache | Lösung |
|---|---|---|
| 502 Bad Gateway | Backend nicht erreichbar | Backend-Service prüfen, Firewall-Regeln |
| 504 Gateway Timeout | Backend antwortet zu langsam | proxy_read_timeout erhöhen |
| 413 Request Entity Too Large | Upload zu groß | client_max_body_size erhöhen |
| WebSocket-Verbindung bricht ab | Upgrade-Header fehlen | Upgrade und Connection Header setzen |
| Backend sieht nur Proxy-IP | Header-Forwarding fehlt | X-Real-IP und X-Forwarded-For setzen |
| Mixed Content-Warnung | Backend generiert HTTP-Links | X-Forwarded-Proto https setzen |
Konfiguration testen
# Syntax prüfen
nginx -t
# Detailliertes Debug-Logging aktivieren
error_log /var/log/nginx/error.log debug;
# Upstream-Antworten loggen
log_format upstream '$remote_addr - $upstream_addr - $upstream_status - $upstream_response_time';
Fazit
Nginx als Reverse Proxy ist der Standard für die sichere Veröffentlichung interner Dienste. TLS-Terminierung mit Let’s Encrypt, WebSocket-Support, Rate Limiting und Security Headers lassen sich mit wenigen Konfigurationszeilen umsetzen. Die Snippet-basierte Konfiguration mit wiederverwendbaren Blöcken hält die Konfiguration DRY und wartbar. Wer interne Dienste ins Internet bringt, sollte das nie ohne Reverse Proxy tun.
Mehr zu diesen Themen:
Weitere Artikel
Backup-Strategie für KMU: Proxmox PBS + TrueNAS als zuverlässiges Backup-Konzept
Backup-Strategie für KMU mit Proxmox PBS und TrueNAS: 3-2-1-Regel umsetzen, PBS als primäres Backup-Target, TrueNAS-Replikation als Offsite-Kopie, Retention Policies und automatisierte Restore-Tests.
OPNsense Suricata Custom Rules: Eigene IDS/IPS-Signaturen schreiben und optimieren
Suricata Custom Rules auf OPNsense: Rule-Syntax, eigene Signaturen für interne Services, Performance-Tuning, Suppress-Lists und EVE-JSON-Logging.
Proxmox Cluster-Netzwerk richtig planen: Corosync, Migration, Storage und Management
Proxmox Cluster-Netzwerk designen: Corosync-Ring, Migration-Network, Storage-Network für Ceph/iSCSI, Management-VLAN, Bonding/LACP und MTU 9000 — mit Beispiel-Topologien.