Sicherer Reverse Proxy mit Nginx Proxy Manager und Docker
Na, alter Hase oder motivierter Neuling? Egal, wo du stehst, willkommen bei smoth.me! Heute nehmen wir uns ein Thema vor, das in jedem Heimlabor, das etwas auf sich hält, eine zentrale Rolle spielt: Den sicheren Zugriff auf deine Dienste von außen. Und nein, ich rede nicht davon, Ports wild aufzureißen. Wir reden über einen Reverse Proxy, genauer gesagt über den Nginx Proxy Manager (NPM), verpackt in Docker-Containern. In meiner Erfahrung ist das eine der elegantesten und benutzerfreundlichsten Lösungen, um deine Home Assistant, N8N, Nextcloud oder was auch immer du sonst so laufen hast, sicher mit SSL-Zertifikaten (dank Let's Encrypt) von außen erreichbar zu machen.
Warum ein Reverse Proxy? Ganz einfach: Er ist dein Türsteher. Anstatt dass jeder deiner Dienste direkt ins Internet lauscht, schickst du den gesamten Traffic über eine einzige, kontrollierte Instanz. Das erhöht die Sicherheit, vereinfacht die Zertifikatsverwaltung und ermöglicht es dir, mehrere Dienste unter verschiedenen Subdomains (z.B. homeassistant.deinedomain.de, n8n.deinedomain.de) über denselben Port (meist 443 für HTTPS) zu erreichen. Wer das zum ersten Mal einrichtet, stolpert oft über DNS-Einstellungen oder Netzwerkprobleme, aber keine Sorge, ich führe dich da durch.
Voraussetzungen – Was du mitbringen solltest
Bevor wir loslegen, lass uns kurz checken, ob du alles am Start hast. Die meisten dieser Punkte sind Standard in einem gut geführten Heimlabor:
- Ein Linux-Server: Das kann ein Raspberry Pi, ein alter PC, eine VM auf Proxmox oder ein dedizierter Server sein. Hauptsache, er läuft stabil und hat genügend Ressourcen (mindestens 1GB RAM, 2 CPU-Kerne für eine reibungslose NPM-Erfahrung, mehr, wenn er noch andere Dienste hostet).
- Docker und Docker Compose: Das ist unsere Basis. Falls du das noch nicht installiert hast, findest du unzählige Guides dazu. Ich gehe davon aus, dass du `docker` und `docker compose` (oder `docker-compose` je nach Version) bereits auf deinem System hast.
- Eine eigene Domain: Zum Beispiel
deinedomain.de. Ohne eine eigene Domain wird es mit Let's Encrypt schwierig und ist auch nicht der Sinn der Sache. - Zugriff auf die DNS-Einstellungen deiner Domain: Du musst A-Records (oder AAAA-Records für IPv6) für deine Subdomains auf die öffentliche IP-Adresse deines Servers zeigen lassen können.
- Geöffnete Ports im Router/Firewall: Die Ports
80(HTTP) und443(HTTPS) müssen von außen auf die IP-Adresse deines Servers weitergeleitet werden. Wichtig: Nur diese beiden Ports! Alles andere bleibt intern. - Grundkenntnisse in der Shell: Wir werden ein paar Befehle eintippen, aber keine Sorge, es ist nichts Kompliziertes.
Schritt-für-Schritt-Anleitung: Nginx Proxy Manager einrichten
Schritt 1: Docker Compose vorbereiten
Zuerst erstellen wir ein Verzeichnis für unsere NPM-Konfiguration. Ich mache das gerne unter /opt/docker, aber du kannst auch einen anderen Pfad wählen. Wichtig ist, dass du deine Konfigurationsdateien nicht verlierst, falls du mal den Server neu aufsetzen musst. Also, legen wir los:
sudo mkdir -p /opt/docker/nginx-proxy-manager
cd /opt/docker/nginx-proxy-manager
Als Nächstes erstellen wir unsere docker-compose.yml Datei. Diese Datei definiert alle Dienste, die wir für Nginx Proxy Manager benötigen:
nano docker-compose.yml
Füge den folgenden Inhalt ein. Ich erkläre dir gleich, was die einzelnen Zeilen bedeuten:
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '81:81'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
environment:
DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "npm_password" # ERSETZE DIESES PASSWORT!
DB_MYSQL_NAME: "npm"
depends_on:
- db
networks:
- default # Für NPM selbst
- proxy-network # Für die Kommunikation mit den Backends
db:
image: 'mariadb:10.6' # Oder postgres:13
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: "npm_root_password" # ERSETZE DIESES PASSWORT!
MYSQL_DATABASE: "npm"
MYSQL_USER: "npm"
MYSQL_PASSWORD: "npm_password" # ERSETZE DIESES PASSWORT!
volumes:
- ./data/mysql:/var/lib/mysql
networks:
- default
networks:
proxy-network:
external: true
default:
# Hier keine besonderen Einstellungen, Docker kümmert sich um die Erstellung
Kurze Erklärung zur docker-compose.yml:
services: Hier definieren wir unsere Container.app: Das ist der Nginx Proxy Manager selbst.image: Wir nutzen das offizielle Docker-Image.restart: unless-stopped: Sorgt dafür, dass der Container nach einem Neustart des Servers oder einem Absturz automatisch wieder startet.ports:80:80und443:443: Das sind die Ports für HTTP und HTTPS, die NPM für deine Proxy-Dienste nutzt. Diese müssen auf deinem Server verfügbar sein und vom Router weitergeleitet werden.81:81: Das ist der Port für die Admin-Oberfläche von Nginx Proxy Manager. Ich empfehle, diesen Port nicht direkt ins Internet zu öffnen, sondern nur lokal zugänglich zu machen oder über einen VPN zu nutzen. Wenn du ihn trotzdem von außen erreichbar machen willst, musst du ihn natürlich auch im Router weiterleiten.
volumes: Hier persistieren wir die Daten../data:/data: Enthält die NPM-Konfiguration und interne Datenbank-Dateien../letsencrypt:/etc/letsencrypt: Hier werden die Let's Encrypt Zertifikate gespeichert. Extrem wichtig, dass diese persistent sind!
environment: Hier konfigurieren wir die Datenbank-Verbindung.depends_on: - db: Stellt sicher, dass die Datenbank vor NPM startet.networks: Hier definieren wir, mit welchen Netzwerken der Container verbunden ist.default: Das Standard-Netzwerk, das Docker Compose für diese Dienste erstellt.proxy-network: Das ist mein Tipp! Ein separates, externes Docker-Netzwerk. In dieses Netzwerk fügst du später all deine anderen Dienste hinzu (Home Assistant, N8N, etc.), die du über NPM proxyn möchtest. So können sie sicher miteinander kommunizieren, ohne dass du Ports in jedem Container einzeln mappen musst.
db: Der Datenbank-Container für NPM. Ich nutze hier MariaDB, da es leichtgewichtig und stabil ist.
networks: Hier definieren wir unsere Docker-Netzwerke.proxy-network: external: true: Bedeutet, dieses Netzwerk wird nicht von diesemdocker-compose.ymlerstellt, sondern muss bereits existieren. Das ist wichtig, damit du es später auch für anderedocker-compose.ymlDateien nutzen kannst.default: Wird automatisch erstellt.
Ganz wichtig: Ändere die Passwörter! Die Platzhalter npm_password und npm_root_password sind unsicher und müssen durch sichere, einzigartige Passwörter ersetzt werden.
Schritt 2: Das externe Docker-Netzwerk erstellen
Da wir ein externes Netzwerk namens proxy-network in unserer docker-compose.yml definiert haben, müssen wir es jetzt erstellen, falls es noch nicht existiert. Das ist ein einmaliger Schritt:
docker network create proxy-network
Wenn du das Netzwerk schon hast (weil du vielleicht schon andere Dienste so betreibst), wird Docker dir einfach sagen, dass es bereits existiert. Kein Problem.
Schritt 3: Nginx Proxy Manager starten
Jetzt wird's spannend! Navigiere in das Verzeichnis, in dem deine docker-compose.yml liegt (/opt/docker/nginx-proxy-manager) und starte die Dienste:
docker compose up -d
Der Parameter -d sorgt dafür, dass die Container im Hintergrund laufen (detached mode). Es kann ein paar Minuten dauern, bis alle Images heruntergeladen und die Container gestartet sind.
Du kannst den Status überprüfen mit:
docker compose ps
Beide Container (app und db) sollten den Status running haben.
Schritt 4: Erste Anmeldung und Einrichtung
Öffne deinen Webbrowser und navigiere zur Admin-Oberfläche von Nginx Proxy Manager. Wenn du den Port 81 nicht nach außen geöffnet hast, musst du das von einem Gerät im selben Netzwerk wie dein Server tun. Die Adresse ist dann:
http://<IP_DEINES_SERVERS>:81
Beim ersten Login sind die Standard-Anmeldedaten:
- Email:
admin@example.com - Password:
changeme
Nach dem ersten Login wirst du aufgefordert, diese Daten zu ändern. Mach das sofort! Wähle ein starkes Passwort und eine gültige E-Mail-Adresse.
Schritt 5: Einen Proxy Host hinzufügen
Jetzt kommt der eigentliche Spaß! Wir fügen einen Proxy Host für einen deiner Dienste hinzu. Nehmen wir an, du hast Home Assistant auf Port 8123 laufen und möchtest es unter homeassistant.deinedomain.de erreichen.
- Navigiere im NPM-Dashboard zu "Hosts" -> "Proxy Hosts".
- Klicke auf "Add Proxy Host".
- Details Tab:
- Domain Names: Gib hier deine gewünschte Subdomain ein, z.B.
homeassistant.deinedomain.de. - Scheme: Meist
http, da die SSL-Verschlüsselung von NPM übernommen wird. - Forward Hostname / IP: Hier gibst du die interne IP-Adresse oder den Docker-Containernamen deines Home Assistant-Dienstes an. Wenn Home Assistant im selben
proxy-networkläuft, kannst du einfach den Containernamen verwenden (z.B.homeassistant). Andernfalls die IP-Adresse des Servers, auf dem HA läuft. - Forward Port: Der interne Port deines Dienstes, z.B.
8123für Home Assistant. - Aktiviere "Block Common Exploits" und "Websockets Support" (letzteres ist wichtig für viele Dienste wie Home Assistant).
- Domain Names: Gib hier deine gewünschte Subdomain ein, z.B.
- SSL Tab:
- Wähle "Request a new SSL Certificate".
- Aktiviere "Force SSL".
- Gib deine E-Mail-Adresse für Let's Encrypt Benachrichtigungen ein.
- Aktiviere "I Agree to the Let's Encrypt Terms of Service".
- Klicke auf "Save".
Wichtig zu wissen: Bevor Let's Encrypt dein Zertifikat ausstellen kann, muss deine Domain (homeassistant.deinedomain.de) auf die öffentliche IP-Adresse deines Servers zeigen. Du musst also in den DNS-Einstellungen deines Domain-Anbieters einen A-Record für homeassistant erstellen, der auf die IP deines Servers verweist. Wenn das nicht korrekt ist, schlägt die Zertifikatsanfrage fehl!
Schritt 6: Wildcard-Zertifikate (Mein Tipp für Fortgeschrittene)
Wenn du viele Subdomains hast (homeassistant.deinedomain.de, n8n.deinedomain.de, grafana.deinedomain.de etc.), ist es mühsam, für jede ein eigenes Zertifikat anzufordern. Hier kommen Wildcard-Zertifikate ins Spiel (z.B. *.deinedomain.de). Ein einziges Zertifikat deckt alle deine Subdomains ab!
Das Anfordern eines Wildcard-Zertifikats erfordert eine DNS-Challenge. Das bedeutet, Let's Encrypt überprüft, ob du die Kontrolle über die Domain hast, indem du einen speziellen TXT-Eintrag in deine DNS-Zone einfügst. NPM kann das automatisch für dich machen, wenn du einen DNS-Provider hast, der von Certbot (der Engine hinter Let's Encrypt) unterstützt wird und du NPM die API-Zugangsdaten gibst (z.B. für Cloudflare).
- Gehe im NPM-Dashboard zu "SSL Certificates".
- Klicke auf "Add SSL Certificate" -> "Let's Encrypt".
- Gib deine Wildcard-Domain ein, z.B.
*.deinedomain.deund zusätzlich die Root-Domaindeinedomain.de(wichtig!). - Aktiviere "Use DNS Challenge".
- Wähle deinen DNS-Provider aus der Liste (z.B.
cloudflare). - Füge die erforderlichen API-Credentials hinzu (z.B. Cloudflare Global API Key und E-Mail). Diese Daten sind sensibel und sollten sicher behandelt werden.
- Aktiviere "I Agree to the Let's Encrypt Terms of Service".
- Klicke auf "Save".
Wenn alles klappt, hast du ein Wildcard-Zertifikat, das du dann für alle deine Proxy Hosts verwenden kannst. Einfach beim Erstellen oder Bearbeiten eines Proxy Hosts im SSL-Tab das neue Wildcard-Zertifikat auswählen.
Häufige Fehler und Lösungen
In meiner Erfahrung stolpert man über ein paar typische Probleme. Hier sind die gängigsten und wie du sie löst:
Problem 1: DNS-Auflösungsprobleme – "Domain does not point to this server"
Wenn du versuchst, ein Let's Encrypt Zertifikat anzufordern und NPM meldet, dass die Domain nicht auf deinen Server zeigt, ist das fast immer ein DNS-Problem.
- Ursache: Der A-Record (oder AAAA-Record für IPv6) deiner Subdomain ist entweder nicht vorhanden, falsch geschrieben oder zeigt auf die falsche IP-Adresse. Let's Encrypt überprüft die öffentliche IP, von der die Anfrage kommt, und vergleicht sie mit dem, was DNS für deine Domain meldet.
- Lösung:
- Überprüfe im DNS-Management deines Domain-Anbieters, ob ein A-Record für
homeassistant.deinedomain.de(oder welche Subdomain du auch immer nutzt) existiert. - Stelle sicher, dass dieser A-Record auf die öffentliche IP-Adresse deines Servers zeigt, nicht auf eine interne LAN-IP.
- Beachte die TTL (Time To Live) des DNS-Eintrags. Es kann bis zu 24 Stunden dauern, bis Änderungen global propagiert werden, auch wenn es oft schneller geht. Nutze Tools wie
digodernslookupauf einem externen System, um die Auflösung zu testen:
Der Befehl sollte die öffentliche IP deines Servers zurückgeben.dig +short homeassistant.deinedomain.de
- Überprüfe im DNS-Management deines Domain-Anbieters, ob ein A-Record für
Problem 2: SSL-Zertifikatfehler – "Connection timed out" oder "Failed to connect to Let's Encrypt"
Wenn NPM keine Verbindung zu den Let's Encrypt Servern herstellen kann, um ein Zertifikat anzufordern.
- Ursache:
- Die Ports 80 und/oder 443 sind auf deinem Router/Firewall nicht korrekt auf deinen Server weitergeleitet.
- Eine Firewall auf deinem Server blockiert ausgehenden oder eingehenden Traffic auf diesen Ports.
- Let's Encrypt Rate Limits wurden erreicht (unwahrscheinlich, aber möglich bei vielen Fehlversuchen).
- Lösung:
- Router-Konfiguration: Überprüfe deine Port-Weiterleitungsregeln (Port Forwarding, NAT) im Router. Port 80 und 443 TCP müssen von außen auf die interne IP-Adresse deines Servers geleitet werden.
- Server-Firewall: Wenn du eine Software-Firewall wie UFW auf deinem Server nutzt, stelle sicher, dass die Ports 80, 443 und 81 (für die Admin-Oberfläche) erlaubt sind:
sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 81/tcp # Nur falls du die Admin-Oberfläche von außen brauchst sudo ufw reload - Let's Encrypt Rate Limits: Wenn du zu viele Zertifikate für dieselbe Domain in kurzer Zeit angefordert hast, kann es sein, dass Let's Encrypt dich temporär blockiert. Warte in diesem Fall ein paar Stunden. Für Tests solltest du die Staging-Umgebung von Let's Encrypt nutzen (Option in NPM unter "SSL Certificates" -> "Let's Encrypt" -> "Use Staging").
Problem 3: "502 Bad Gateway" oder "Connection Refused"
Diese Fehler treten auf, wenn NPM den Traffic zwar empfängt, aber die Verbindung zu deinem internen Dienst (z.B. Home Assistant) nicht herstellen kann.
- Ursache:
- Der interne Dienst läuft nicht oder ist nicht erreichbar.
- Falscher "Forward Hostname / IP" oder "Forward Port" im Proxy Host von NPM.
- Netzwerkprobleme zwischen NPM und dem Backend-Dienst (z.B. der Backend-Dienst ist nicht im
proxy-network).
- Lösung:
- Dienststatus prüfen: Stelle sicher, dass dein Backend-Dienst (z.B. Home Assistant) läuft und intern erreichbar ist. Versuch mal, ihn direkt über seine interne IP und Port aufzurufen (z.B.
http://<interne_HA_IP>:8123). - NPM-Konfiguration prüfen: Geh in NPM zu deinem Proxy Host und überprüfe den "Forward Hostname / IP" und "Forward Port". Sind sie korrekt?
- Wenn dein Backend-Dienst ein Docker-Container ist und im selben
proxy-networkwie NPM läuft, kannst du den Containernamen als "Forward Hostname" verwenden (z.B.homeassistant). Das ist die sauberste Lösung. - Läuft der Dienst auf einem anderen Server oder direkt auf dem Host, gib die interne IP-Adresse des Servers an.
- Wenn dein Backend-Dienst ein Docker-Container ist und im selben
- Docker-Netzwerk: Wenn du das
proxy-networknutzt, stelle sicher, dass dein Backend-Dienst auch in diesem Netzwerk ist. Wenn du z.B. Home Assistant mit Docker Compose betreibst, sollte deinedocker-compose.ymlfür Home Assistant ungefähr so aussehen:services: homeassistant: image: ghcr.io/home-assistant/home-assistant:stable restart: unless-stopped ports: - 8123:8123 # Diesen Port nur mappen, wenn du HA auch intern direkt erreichen willst volumes: - ./config:/config environment: TZ: Europe/Berlin networks: - proxy-network # HIER IST DER WICHTIGE PUNKT! networks: proxy-network: external: true
- Dienststatus prüfen: Stelle sicher, dass dein Backend-Dienst (z.B. Home Assistant) läuft und intern erreichbar ist. Versuch mal, ihn direkt über seine interne IP und Port aufzurufen (z.B.
Fazit und nächste Schritte
Herzlichen Glückwunsch! Du hast jetzt einen voll funktionsfähigen und sicheren Reverse Proxy mit Nginx Proxy Manager auf deinem Server am Laufen. Das ist ein riesiger Schritt für jedes Heimlabor, da es dir nicht nur Sicherheit und Komfort bietet, sondern auch die Basis für viele weitere spannende Projekte legt.
Was kommt als Nächstes?
- Absicherung der Admin-Oberfläche: Überlege, den Port 81 nicht nach außen zu öffnen und stattdessen nur über einen VPN-Zugang auf die NPM-Oberfläche zuzugreifen. Das ist der sicherste Weg.
- Authentifizierung vor dem Proxy: Für noch mehr Sicherheit kannst du Dienste wie Authelia oder Authentik vor NPM schalten, um eine 2-Faktor-Authentifizierung für deine Dienste zu erzwingen, selbst wenn der Dienst selbst keine hat.
- Caching und erweiterte Nginx-Konfigurationen: NPM bietet auch die Möglichkeit, benutzerdefinierte Nginx-Konfigurationen einzufügen, um z.B. Caching zu aktivieren oder spezielle Header zu setzen. Das ist dann aber schon für die ganz Fortgeschrittenen unter euch.
Ich hoffe, dieser Guide hat dir geholfen, deine Dienste sicher und elegant ins Netz zu bringen. Viel Spaß beim Experimentieren in deinem Heimlabor!