Warum ein Reverse Proxy?

Du hast dein Homelab aufgesetzt, Docker läuft, und ein halbes Dutzend Self-Hosted Dienste sind am Start. Jetzt tippst du im Browser:

  • Proxmox: https://192.168.1.100:8006
  • Portainer: https://192.168.1.110:9443
  • Nextcloud: http://192.168.1.110:8080
  • Jellyfin: http://192.168.1.110:8096
  • Zabbix: http://192.168.1.110:8080 — Moment, das war doch schon Nextcloud?

Genau. Du merkst dir IP-Adressen und Ports. Du hast keine SSL-Zertifikate, weil Let’s Encrypt nicht mit IP-Adressen funktioniert. Und von unterwegs erreichst du nichts, weil du nicht für jeden Service einen Port im Router freigeben willst (und solltest).

Ein Reverse Proxy löst alle drei Probleme auf einmal.

Was ein Reverse Proxy tut

Internet/Browser
       │
       ▼
┌──────────────────────────┐
│   Reverse Proxy (:443)   │
│   ─────────────────────  │
│   nextcloud.domain.de ──────→ 192.168.1.110:8080
│   jellyfin.domain.de  ──────→ 192.168.1.110:8096
│   zabbix.domain.de    ──────→ 192.168.1.110:8081
│   proxmox.domain.de   ──────→ 192.168.1.100:8006
│   ─────────────────────  │
│   ✅ SSL für alle         │
│   ✅ Ein Port (443)       │
│   ✅ Saubere URLs         │
└──────────────────────────┘

Der Proxy nimmt alle HTTPS-Anfragen auf Port 443 entgegen. Anhand des Hostnamens (aus dem HTTP-Header) entscheidet er, an welchen internen Service weitergeleitet wird. Der Browser sieht eine saubere URL mit gültigem SSL-Zertifikat. Deine internen Services müssen nicht wissen, dass sie hinter einem Proxy stehen.

Vorteile auf einen Blick

ProblemOhne Reverse ProxyMit Reverse Proxy
URLhttp://192.168.1.110:8096https://jellyfin.mein-homelab.de
SSLSelbstsigniert (Browser-Warnung)Let’s Encrypt (grünes Schloss)
Externer ZugriffPort-Forwarding pro ServiceEin Port (443) für alles
SicherheitJeder Service direkt exponiertEin Eintrittspunkt, zentrale Firewall
Merken15 verschiedene IPs und PortsSaubere Subdomains

Domain und DNS: Die Grundlage

Bevor wir den Proxy einrichten, brauchst du eine Domain. Ohne Domain kein SSL-Zertifikat von Let’s Encrypt, ohne SSL keine sichere Verbindung.

Domain kaufen

Eine .de-Domain kostet 5-10€ pro Jahr. Registrare wie Netcup, Hetzner, INWX oder Cloudflare Registrar (oft am günstigsten) bieten das an. Ich empfehle einen Registrar, der auch DNS-Hosting macht — das vereinfacht einiges.

Für diesen Guide nehmen wir mein-homelab.de als Beispiel.

DNS konfigurieren

Du brauchst zwei Dinge:

Für internen Zugriff (Split DNS):

Wenn du nur innerhalb deines Heimnetzwerks auf die Services zugreifen willst (kein Zugriff von unterwegs), reicht eine lokale DNS-Konfiguration:

  • In deinem Pi-hole oder lokalen DNS-Server: Wildcard-Eintrag *.mein-homelab.de → 192.168.1.110 (die IP deines Reverse Proxy)
  • Oder: Einzelne A-Records für jeden Service
# Pi-hole Custom DNS (unter /etc/dnsmasq.d/04-homelab.conf)
address=/mein-homelab.de/192.168.1.110

Das leitet alle Subdomains von mein-homelab.de auf deinen Proxy. Intern. Ohne dass irgendwas ins Internet exponiert wird.

Für externen Zugriff (Zugriff von unterwegs):

Bei deinem Domain-Registrar:

TypNameZielTTL
Amein-homelab.deDeine öffentliche IP300
CNAME*.mein-homelab.demein-homelab.de300

Deine öffentliche IP findest du unter ifconfig.me. Bei dynamischer IP (die meisten DSL-Anschlüsse) brauchst du einen DynDNS-Dienst — dazu gleich mehr.

DynDNS für dynamische IPs

Die meisten Heim-Internetanschlüsse haben eine dynamische IP, die sich alle 24h ändert. Lösungen:

  • Fritz!Box eingebautes DynDNS: Unter Internet → Freigaben → DynDNS. Unterstützt Anbieter wie myfritz, No-IP, DynDNS.
  • ddclient: Linux-Tool, das deine IP bei diversen DNS-Anbietern aktualisiert. Läuft als Docker-Container.
  • Cloudflare API: Wenn dein DNS bei Cloudflare liegt, gibt’s dutzende kleine Tools die deine IP automatisch updaten. Mein Favorit: cloudflare-ddns als Container.
# DynDNS mit Cloudflare (Docker)
services:
  cloudflare-ddns:
    image: oznu/cloudflare-ddns:latest
    container_name: cloudflare-ddns
    restart: unless-stopped
    environment:
      - API_KEY=dein-cloudflare-api-token
      - ZONE=mein-homelab.de
      - SUBDOMAIN=*
      - PROXIED=false

DNS-Challenge für Wildcard-Zertifikate

Kleiner Vorgriff: Für Wildcard-SSL-Zertifikate (*.mein-homelab.de) brauchst du die DNS-01 Challenge von Let’s Encrypt. Das heißt, dein SSL-Tool muss DNS-Einträge automatisch erstellen können. Unterstützte DNS-Provider: Cloudflare, Hetzner DNS, INWX, Route53, und viele mehr. Cloudflare ist hier am einfachsten — kostenloser DNS mit API, gut dokumentiert, weitverbreitet.


Option 1: Nginx Proxy Manager (Empfohlen für Einsteiger)

Nginx Proxy Manager (NPM) ist Nginx mit einer Web-Oberfläche. Du klickst statt zu konfigurieren. SSL-Zertifikate per Knopfdruck. Für 90% aller Homelab-Setups mehr als ausreichend.

Installation

mkdir -p /opt/docker/nginx-proxy-manager
cat > /opt/docker/nginx-proxy-manager/docker-compose.yml << 'EOF'
services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"      # HTTP
      - "443:443"    # HTTPS
      - "81:81"      # Admin-GUI
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    environment:
      - TZ=Europe/Berlin
EOF

cd /opt/docker/nginx-proxy-manager
docker compose up -d

Erster Login unter http://DEINE-IP:81:

  • Email: admin@example.com
  • Passwort: changeme

Sofort ändern. Ernst gemeint — Port 81 ist der Admin-Zugang zu deinem gesamten Reverse Proxy.

SSL-Zertifikat einrichten

Bevor du Proxy-Hosts konfigurierst: SSL-Zertifikat holen.

  1. SSL Certificates → Add SSL Certificate → Let’s Encrypt
  2. Domain Names: *.mein-homelab.de und mein-homelab.de
  3. Email: Deine Email
  4. Use a DNS Challenge: ✅ (Pflicht für Wildcard!)
  5. DNS Provider: Cloudflare (oder deinen Anbieter)
  6. API Token eintragen
  7. Save → NPM holt automatisch das Zertifikat

Das Wildcard-Zertifikat gilt für alle Subdomains. Du musst es nur einmal einrichten, und jeder neue Service bekommt automatisch SSL. Kein weiteres Zertifikat-Klicken mehr.

Ersten Proxy Host einrichten

Beispiel: Nextcloud unter nextcloud.mein-homelab.de erreichbar machen.

  1. Hosts → Proxy Hosts → Add Proxy Host
  2. Details:
    • Domain Names: nextcloud.mein-homelab.de
    • Scheme: http
    • Forward Hostname: 192.168.1.110 (IP des Docker-Hosts wo Nextcloud läuft)
    • Forward Port: 8080
    • Block Common Exploits: ✅
    • Websockets Support: ✅ (brauchen manche Apps)
  3. SSL:
    • SSL Certificate: Dein Wildcard-Zertifikat auswählen
    • Force SSL: ✅
    • HTTP/2 Support: ✅
    • HSTS Enabled: ✅ (sagt dem Browser: nur HTTPS, nie HTTP)

Save. Fertig. https://nextcloud.mein-homelab.de funktioniert jetzt mit gültigem SSL.

Weitere Services hinzufügen

Gleicher Prozess für jeden Service:

SubdomainZiel-IPZiel-PortBesonderheiten
jellyfin.mein-homelab.de192.168.1.1108096Websockets ✅
portainer.mein-homelab.de192.168.1.1109443Scheme: https
zabbix.mein-homelab.de192.168.1.1108080
proxmox.mein-homelab.de192.168.1.1008006Scheme: https, Websockets ✅
pihole.mein-homelab.de192.168.1.12080

Wichtig bei Portainer und Proxmox: Die laufen selbst schon auf HTTPS (selbstsigniert). Im NPM stellst du dann “Scheme” auf https — der Proxy verbindet sich per HTTPS zum Backend, aber der Browser sieht das gültige Let’s Encrypt-Zertifikat.

Access Lists: Wer darf was?

Nicht jeder Service sollte für die ganze Welt erreichbar sein. NPM hat eingebaute Access Lists:

  1. Access Lists → Add Access List
  2. Name: Nur intern
  3. Access: Allow 192.168.1.0/24, Deny all
  4. Oder: Basic Auth hinzufügen (Benutzername + Passwort als erste Hürde)

Dann in den Proxy-Host-Einstellungen die Access List zuweisen. Portainer und Proxmox würde ich nie ohne Zugriffsbeschränkung ins Internet stellen. Auch nicht mit starkem Passwort. Die Angriffsfläche ist einfach zu groß.


Option 2: Nginx manuell konfigurieren (Für Fortgeschrittene)

Wenn du mehr Kontrolle willst oder NPM dir zu “klickibunti” ist. Der manuelle Weg gibt dir volle Flexibilität, aber du schreibst Nginx-Configs von Hand.

Nginx + Certbot installieren

mkdir -p /opt/docker/nginx-manual
cat > /opt/docker/nginx-manual/docker-compose.yml << 'EOF'
services:
  nginx:
    image: nginx:alpine
    container_name: nginx-reverse-proxy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./conf.d:/etc/nginx/conf.d
      - ./ssl:/etc/nginx/ssl
      - ./certbot-webroot:/var/www/certbot
      - ./letsencrypt:/etc/letsencrypt
    environment:
      - TZ=Europe/Berlin

  certbot:
    image: certbot/certbot:latest
    container_name: certbot
    volumes:
      - ./certbot-webroot:/var/www/certbot
      - ./letsencrypt:/etc/letsencrypt
EOF

Nginx-Konfiguration pro Service

Jeder Service bekommt eine eigene Config-Datei. Beispiel für Nextcloud:

mkdir -p /opt/docker/nginx-manual/conf.d
cat > /opt/docker/nginx-manual/conf.d/nextcloud.conf << 'NGINXEOF'
server {
    listen 80;
    server_name nextcloud.mein-homelab.de;
    
    # Certbot ACME Challenge
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
    
    # Alles andere → HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name nextcloud.mein-homelab.de;

    ssl_certificate /etc/letsencrypt/live/mein-homelab.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mein-homelab.de/privkey.pem;
    
    # SSL Hardening
    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_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    
    # Security Headers
    add_header Strict-Transport-Security "max-age=31536000; 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;
    
    # Proxy zum Backend
    location / {
        proxy_pass http://192.168.1.110:8080;
        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;
        
        # Für große Datei-Uploads (Nextcloud!)
        client_max_body_size 10G;
        proxy_request_buffering off;
        
        # Websockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
NGINXEOF

SSL-Zertifikat mit Certbot holen

# Erstmaliges Zertifikat (HTTP-Challenge für einzelne Domains):
docker compose run --rm certbot certonly \
  --webroot -w /var/www/certbot \
  -d nextcloud.mein-homelab.de \
  -d jellyfin.mein-homelab.de \
  --email deine@email.de \
  --agree-tos \
  --no-eff-email

# Für Wildcard (DNS-Challenge mit Cloudflare):
docker compose run --rm certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d "*.mein-homelab.de" \
  -d "mein-homelab.de" \
  --email deine@email.de \
  --agree-tos

Auto-Renewal per Cron

Let’s Encrypt-Zertifikate laufen nach 90 Tagen ab. Certbot erneuert sie automatisch — du musst nur dafür sorgen, dass es regelmäßig versucht wird:

# Cronjob: 2x täglich prüfen, ob Erneuerung nötig
(crontab -l 2>/dev/null; echo "0 3,15 * * * cd /opt/docker/nginx-manual && docker compose run --rm certbot renew --quiet && docker compose exec nginx nginx -s reload") | crontab -

Option 3: Traefik (Für Docker-Power-User)

Traefik ist der Liebling der Docker-Community. Statt per Klick oder Config-Datei konfigurierst du den Proxy über Docker Labels. Neuer Container mit den richtigen Labels → Traefik erkennt ihn automatisch und erstellt die Route. Kein Reload nötig.

Warum Traefik?

  • Auto-Discovery: Neuer Container startet → Traefik erkennt ihn sofort
  • Zero-Downtime: Kein nginx reload nötig
  • Mittels Labels: Die Proxy-Config steht direkt in der docker-compose.yml des Services
  • Middleware: Rate-Limiting, Basic Auth, IP-Whitelist — als Labels am Container

Traefik installieren

# /opt/docker/traefik/docker-compose.yml
services:
  traefik:
    image: traefik:v3.3
    container_name: traefik
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/etc/traefik/traefik.yml
      - ./acme.json:/acme.json
      - ./dynamic:/etc/traefik/dynamic
    environment:
      - CF_DNS_API_TOKEN=dein-cloudflare-token
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.mein-homelab.de`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.routers.dashboard.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$05$$..."
    networks:
      - proxy

networks:
  proxy:
    name: proxy
    external: true
# /opt/docker/traefik/traefik.yml
api:
  dashboard: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letsencrypt
        domains:
          - main: mein-homelab.de
            sans:
              - "*.mein-homelab.de"

providers:
  docker:
    exposedByDefault: false
    network: proxy
  file:
    directory: /etc/traefik/dynamic
    watch: true

certificatesResolvers:
  letsencrypt:
    acme:
      email: deine@email.de
      storage: acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"

log:
  level: WARN

Service mit Traefik-Labels

So sieht ein Docker-Service mit Traefik-Labels aus:

# Beispiel: Nextcloud mit Traefik
services:
  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    restart: unless-stopped
    volumes:
      - ./html:/var/www/html
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nextcloud.rule=Host(`nextcloud.mein-homelab.de`)"
      - "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
      - "traefik.http.services.nextcloud.loadbalancer.server.port=80"
      # Middleware für große Uploads:
      - "traefik.http.middlewares.nextcloud-body.buffering.maxRequestBodyBytes=10737418240"
    networks:
      - proxy
      - default

networks:
  proxy:
    external: true

Kein Reload, kein manuelles Zertifikat. Container starten → Traefik macht den Rest.

NPM vs. Traefik: Wann was?

AspektNginx Proxy ManagerTraefik
KonfigurationWeb-GUI (klicken)Docker Labels + YAML
LernkurveFlach — intuitivSteil — Labels, Middleware, Entrypoints
Auto-DiscoveryNein (manuell)Ja (Docker-native)
Non-Docker ServicesEinfach (IP:Port eintragen)Möglich, aber per File-Provider
Updatesdocker compose pulldocker compose pull
Ressourcen~100 MB RAM~50 MB RAM
Ideal fürEinsteiger, gemischte UmgebungenDocker-only, DevOps-Fans

Meine Empfehlung: Fang mit NPM an. Wenn dir die GUI irgendwann zu einschränkend wird oder du alles in Code haben willst, migriere zu Traefik. Beide machen den gleichen Job, der Weg dorthin ist nur unterschiedlich.


Sicherheit: Der Proxy als Schutzschild

Dein Reverse Proxy ist der einzige Punkt, der nach außen exponiert ist. Das ist gleichzeitig die Stärke (ein Punkt zu schützen) und die Schwachstelle (fällt der, fällt alles). Deswegen:

SSL-Konfiguration härten

# Nur moderne Protokolle (TLS 1.2 und 1.3)
ssl_protocols TLSv1.2 TLSv1.3;

# HSTS: Browser merkt sich "nur HTTPS" für ein Jahr
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# Kein Embedding in Frames (Clickjacking-Schutz)
add_header X-Frame-Options "SAMEORIGIN" always;

# MIME-Type-Sniffing verhindern
add_header X-Content-Type-Options "nosniff" always;

Tipp: Teste deine SSL-Konfiguration unter SSL Labs. Ziel: A+ Rating. Mit den obigen Einstellungen erreichst du das.

Rate Limiting

Schützt vor Brute-Force-Angriffen auf Login-Seiten:

# In der nginx.conf (http-Block):
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/s;

# In der Server-Config:
location /login {
    limit_req zone=login burst=10 nodelay;
    proxy_pass http://backend;
}

Oder in NPM: Custom Nginx Configuration pro Proxy Host → dort eigene Rate-Limits eintragen.

Fail2ban für den Reverse Proxy

Fail2ban kann Nginx-Logs auswerten und IPs sperren, die zu viele fehlerhafte Anfragen stellen:

apt install fail2ban -y

cat > /etc/fail2ban/jail.local << 'EOF'
[nginx-botsearch]
enabled  = true
port     = http,https
logpath  = /opt/docker/nginx-proxy-manager/data/logs/proxy-host-*_access.log
maxretry = 10
findtime = 60
bantime  = 3600

[nginx-http-auth]
enabled  = true
port     = http,https
logpath  = /opt/docker/nginx-proxy-manager/data/logs/proxy-host-*_error.log
maxretry = 5
bantime  = 3600
EOF

systemctl restart fail2ban

Authelia / Authentik: Single Sign-On

Für zusätzliche Sicherheit kannst du einen SSO-Gateway vor deine Services schalten. Authelia oder Authentik fungieren als Login-Portal — jeder Request muss erst durch das Portal, bevor er zum Service weitergeleitet wird.

Das bedeutet: Selbst wenn eine Software eine Sicherheitslücke hat, kommt niemand dran, ohne sich vorher bei Authelia authentifiziert zu haben. Mit 2FA (TOTP oder WebAuthn/FIDO2) ist das eine verdammt starke Absicherung.

Authelia läuft als Docker-Container und integriert sich nahtlos in NPM und Traefik. Das ist aber einen eigenen Artikel wert — hier nur der Hinweis, dass es existiert und sich lohnt.


Services von unterwegs erreichbar machen

Hier wird’s ernst: Du öffnest Ports in deinem Router. Das heißt, dein Homelab ist aus dem Internet erreichbar. Das birgt Risiken. Mach es nur, wenn du weißt was du tust, und befolge die Sicherheitstipps oben.

Option A: Port-Forwarding (Direkt)

In deinem Router (z.B. Fritz!Box):

  1. Internet → Freigaben → Portfreigaben → Neue Freigabe
  2. Gerät: Dein Reverse-Proxy-Host
  3. Port 80 und 443 weiterleiten
  4. Fertig

Jetzt ist alles, was der Reverse Proxy bedient, von außen erreichbar. Genau deshalb ist es so wichtig, dass nur der Proxy nach außen zeigt und nicht die einzelnen Services direkt.

Option B: Cloudflare Tunnel (Kein offener Port nötig)

Wenn du keine Ports öffnen willst (oder kannst — manche Provider blocken das), ist ein Cloudflare Tunnel die eleganteste Lösung:

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared
    restart: unless-stopped
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=dein-tunnel-token

Der Tunnel baut eine ausgehende Verbindung zu Cloudflare auf. Kein eingehender Port nötig, kein Port-Forwarding, keine Firewall-Regeln. Cloudflare routet den Traffic über den Tunnel zu deinem Reverse Proxy.

Nachteile: Dein gesamter Traffic läuft über Cloudflare. Die können theoretisch mitlesen (sie terminieren SSL). Für ein Homelab mit Nextcloud und Jellyfin ist das in der Praxis kein Problem — für wirklich sensible Dinge (Vaultwarden) würde ich eher ein VPN nutzen.

Option C: VPN (Am sichersten)

Die sicherste Variante: Gar keine Ports öffnen. Stattdessen WireGuard-VPN einrichten und von unterwegs zuerst ins VPN verbinden. Dann bist du im lokalen Netz und erreichst alles wie zuhause.

Vorteil: Keinerlei Angriffsfläche von außen. Nachteil: Du musst zuerst VPN aktivieren. Für Sharing mit Familie oder Freunden unpraktisch.

Mein Setup: WireGuard für den persönlichen Zugriff + Cloudflare Tunnel für Services, die ich mit anderen teilen will (Jellyfin Familienzugang, Nextcloud-Shares).


Troubleshooting: Die häufigsten Probleme

502 Bad Gateway

Der Proxy kann den Backend-Service nicht erreichen.

Checkliste:

  1. Läuft der Backend-Service? → docker ps oder systemctl status
  2. IP und Port korrekt?
  3. Backend auf http oder https? (Proxmox/Portainer nutzen HTTPS!)
  4. Container im richtigen Docker-Netzwerk? (bei Traefik muss der Container im proxy-Netzwerk sein)
  5. Firewall auf dem Docker-Host? → iptables -L -n oder ufw status

SSL-Zertifikat wird nicht ausgestellt

DNS-Challenge (Wildcard):

  • API-Token korrekt? Hat der Token die richtigen Permissions?
  • DNS-Provider richtig konfiguriert?
  • docker compose logs certbot oder NPM-Logs prüfen

HTTP-Challenge:

  • Port 80 von außen erreichbar? → canyouseeme.org auf Port 80 testen
  • DNS zeigt auf die richtige IP?
  • .well-known/acme-challenge/ wird nicht von einem anderen Location-Block abgefangen?

“Too many redirects”

Klassiker. Passiert, wenn der Proxy HTTPS erzwingt, aber der Backend-Service auch HTTPS erzwingt, und beide sich gegenseitig umleiten.

Lösung: Im Backend-Service (z.B. Nextcloud) konfigurieren, dass es hinter einem Proxy läuft:

// Nextcloud config/config.php:
'overwriteprotocol' => 'https',
'trusted_proxies' => ['192.168.1.110'],  // IP des Reverse Proxy

Websocket-Verbindungen brechen ab

Passiert bei Services wie Proxmox Console, Portainer, Vaultwarden, oder Uptime Kuma.

Lösung: Websocket-Support im Proxy aktivieren:

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

In NPM: “Websockets Support” ✅ in den Proxy-Host-Einstellungen.

Upload-Limits

Nextcloud-Upload bricht bei 1 MB ab? Der Proxy hat ein Body-Size-Limit:

# Für Nextcloud: 10 GB erlauben
client_max_body_size 10G;
proxy_request_buffering off;

In NPM: Custom Nginx Configuration des Proxy Hosts:

client_max_body_size 10G;
proxy_request_buffering off;

Performance-Optimierung

Caching für statische Assets

Dein Proxy kann statische Dateien cachen, sodass sie nicht jedes Mal vom Backend geholt werden:

# In der Proxy-Config:
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ {
    proxy_pass http://backend;
    expires 30d;
    add_header Cache-Control "public, immutable";
}

Gzip/Brotli Kompression

Falls der Backend-Service keine Kompression macht (viele Docker-Images tun’s nicht):

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript image/svg+xml;
gzip_min_length 256;
gzip_vary on;

Reduziert den Traffic um 60-80% für Textinhalte. Besonders spürbar bei mobilem Zugriff.

HTTP/2 und HTTP/3

HTTP/2 ist bei NPM und Traefik standardmäßig aktiv. HTTP/3 (QUIC) bietet nochmal bessere Performance bei instabilen Verbindungen (Mobilfunk):

In Traefik:

entryPoints:
  websecure:
    address: ":443"
    http3: {}

In NPM: HTTP/2 ist per Default an, HTTP/3 muss man über Custom Config aktivieren.


Monitoring: Weiß dein Proxy noch was er tut?

Dein Reverse Proxy ist kritische Infrastruktur. Wenn er down ist, sind alle Services down. Also: überwachen.

Mit Zabbix

Wenn du den Zabbix-Guide befolgt hast:

  1. Zabbix Agent auf dem Proxy-Host installieren
  2. Template “Nginx by Zabbix agent” zuweisen
  3. Nginx Status-Seite aktivieren:
server {
    listen 127.0.0.1:8888;
    location /nginx_status {
        stub_status;
        allow 127.0.0.1;
        deny all;
    }
}

Jetzt überwacht Zabbix: Active Connections, Requests/s, Accepted/Handled, und alarmiert wenn Nginx nicht mehr antwortet.

Mit Uptime Kuma

Einfacher: In Uptime Kuma für jeden Proxy-Host einen HTTP-Monitor einrichten. Damit weißt du zumindest, ob die Services von außen erreichbar sind.


Nächste Schritte

Dein Reverse Proxy steht. Alle Services sind über saubere URLs mit SSL erreichbar. Was jetzt?

  1. Authelia oder Authentik einrichten für Single Sign-On und 2FA vor allen Services
  2. Monitoring konfigurieren — SSL-Ablaufdaten überwachen, Proxy-Status, Response-Times
  3. Crowdsec installieren — Community-basierte IP-Blocklisten, integriert sich direkt in Nginx
  4. Automatische Backups der Proxy-Konfiguration (NPM: das data/-Verzeichnis sichern, Traefik: acme.json + die YAML-Configs)

Fazit

Ein Reverse Proxy verwandelt dein Homelab vom Bastelprojekt mit IP:Port-Bookmarks in eine professionelle Infrastruktur mit sauberen URLs und gültigem SSL. Nginx Proxy Manager hat die gesamte Einrichtung auf ein paar Klicks reduziert — es gibt keine Ausrede mehr, Services ohne HTTPS zu betreiben.

Die Kombination aus Wildcard-Zertifikat, Split-DNS für intern und WireGuard oder Cloudflare Tunnel für extern ist meiner Erfahrung nach das beste Setup fürs Homelab. Neue Services hinzufügen dauert 30 Sekunden statt 30 Minuten. Und das grüne Schloss im Browser fühlt sich jedes Mal ein bisschen gut an.

Fang mit NPM an, richte 2-3 Services ein, und du wirst nie wieder 192.168.1.110:8096 in die Adressleiste tippen.


Zuletzt aktualisiert: Februar 2026 | Nginx Proxy Manager 2.x | Traefik 3.x | Let’s Encrypt