Irgendwann hat jedes Homelab dieselbe Zettelwirtschaft: Uptime Kuma hört auf Port 3001, der nächste Dienst auf 8080, der dritte auf 9000, und du merkst dir die Nummern wie Telefonnummern aus einer Zeit ohne Adressbuch. Dazu meckert der Browser bei jedem Aufruf über die fehlende sichere Verbindung, und zwar bei jedem Dienst einzeln. Ein Reverse Proxy räumt beides mit einem Handgriff auf. Was er genau tut, warum er im Homelab so früh sinnvoll ist und wie du einen in einer halben Stunde laufen hast, steht hier.

Kurz gesagt: Ein Reverse Proxy ist die eine Eingangstür für alle deine Dienste. Du tippst einen Namen statt IP und Port, und HTTPS gibt es an einer Stelle statt in jedem Container. Am Ende läuft Nginx Proxy Manager bei dir, und Uptime Kuma ist unter einem eigenen Namen erreichbar. Dauer rund 30 Minuten, Stufe Einsteiger. Stand: Nginx Proxy Manager 2.15.1, geprüft am 07-09-2026.
Schaubild: Der Browser fragt nach kuma.home.arpa, der Reverse Proxy liest den Namen und reicht die Anfrage an uptime-kuma:3001 weiter, der Dienst antwortet über den Proxy
Der Weg einer Anfrage: Browser, Reverse Proxy, Dienst. Der Proxy ist die einzige offene Tür.

Das Problem: viele Dienste, viele Ports, viele Warnungen

Ein Dienst im Docker-Container macht sich über einen Port erreichbar. Das ist praktisch, solange es ein Dienst ist. Beim fünften tippst du 192.168.178.20:3001, 192.168.178.20:8080 und so weiter, und niemand in deinem Haushalt außer dir weiß, welche Nummer zu was gehört. Verschlüsselung bekommt jeder Dienst einzeln, wenn er sie überhaupt kann, und Zertifikate verwaltest du dann an fünf Stellen.

Ein Reverse Proxy stellt sich vor all diese Dienste. Nach außen zeigt er nur noch eine Tür: Port 80 für HTTP und Port 443 für HTTPS. Alles, was an diese Tür klopft, nimmt er entgegen und reicht es an den richtigen Dienst weiter.

Reverse Proxy? Der Empfang im Bürogebäude. Du sagst am Tresen, zu wem du willst, und wirst in den richtigen Raum gebracht. Welche Zimmernummer das ist, musst du nie wissen, und die Bürotüren selbst sind für Besucher von der Straße gar nicht erreichbar.

Das Wort „Reverse“ verwirrt gern. Ein normaler Proxy, so erklärt es die Mozilla-Dokumentation, handelt im Auftrag des Nutzers und verbirgt dessen Identität gegenüber den Servern. Der Reverse Proxy macht es umgekehrt: Er handelt im Auftrag der Server und verbirgt sie gegenüber den Nutzern. Im Homelab bist du beides, Nutzer und Betreiber, deshalb fühlt sich die Unterscheidung erst mal akademisch an. Merken kannst du dir: Der Reverse Proxy steht auf der Seite deiner Dienste.

Was mit einer Anfrage passiert

Browser→ kuma.home.arpa, Port 80/443 →Reverse Proxy→ uptime-kuma:3001 →Uptime Kuma

Dein Browser schickt bei jeder Anfrage den Namen mit, den du eingetippt hast. Genau dieser Name ist der Schlüssel: Der Proxy sieht „kuma.home.arpa“, schaut in seine Liste, findet den Eintrag „gehört zu uptime-kuma auf Port 3001“ und reicht die Anfrage dorthin weiter. Die Antwort nimmt denselben Weg zurück. Uptime Kuma merkt davon wenig, es sieht nur eine Anfrage vom Proxy.

Drei Dinge folgen daraus, und wegen dieser drei lohnt sich der Aufwand:

  • Namen statt Portnummern. Ein Eintrag pro Dienst, und die Zahlen sind aus deinem Kopf verschwunden.
  • HTTPS an einer Stelle. Der Proxy hält die Zertifikate und verschlüsselt zum Browser. Die Dienste dahinter dürfen im internen Netz weiter schlichtes HTTP sprechen.
  • Weniger offene Türen. Die Dienste brauchen keinen eigenen veröffentlichten Port mehr. Nur der Proxy ist erreichbar, und der ist die eine Stelle, die du im Blick behältst.
Zertifikat? Der Ausweis einer Webseite. Der Browser prüft ihn, bevor er das grüne Schloss zeigt. Let's Encrypt stellt solche Ausweise kostenlos aus, laut eigener FAQ mit 90 Tagen Gültigkeit, und der Proxy verlängert sie selbst, bevor sie ablaufen.

Für die Praxis nehme ich Nginx Proxy Manager. Der Grund steht in einem Satz des Entwicklers auf der Projektseite: Er wollte Weiterleitungen und Zertifikate einrichten können, „ohne zu viel über Nginx oder Letsencrypt wissen zu müssen“. Das ist genau die Stufe dieser Anleitung. Alles läuft in einer Weboberfläche mit Formularen, und der Nginx darunter bleibt für dich unsichtbar. Wer später Konfigurationsdateien lieber mag, findet mit Caddy oder Traefik andere Türsteher; das Prinzip ist dasselbe.

So liest du diese Anleitung: Alles, was du selbst tun sollst, steht in einem farbigen Kasten. [ per klick ] heißt: Das erledigst du mit der Maus in einer Web-Oberfläche, hier die Oberfläche von Nginx Proxy Manager. [ über die shell ] heißt: Den Befehl kopieren, ins Terminal einfügen, Enter. Stehen beide Kästen direkt untereinander, führen sie zum selben Ergebnis. Du gehst EINEN davon, nicht beide.

Was du brauchst

  • Einen Linux-Rechner mit Docker und Docker Compose. Ein alter Büro-PC, ein Mini-PC oder eine VM reichen völlig.
  • Die Ports 80 und 443 auf diesem Rechner müssen frei sein. Genau die will der Proxy haben.
  • Einen laufenden Dienst zum Ausprobieren. Ich nehme Uptime Kuma, weil es klein ist und du es vielleicht nach unserer Anleitung schon laufen hast.

Ob der Rechner bereit ist, siehst du mit drei Befehlen:

docker --version
docker compose version
sudo ss -tulpn | grep -E ':(80|443) '

Die ersten beiden Befehle antworten mit einer Versionszeile, etwa Docker version 28.x und Docker Compose version v2.x. Der dritte darf gar nichts ausgeben: Leere Ausgabe heißt, niemand belegt Port 80 oder 443. Zeigt er eine Zeile, läuft dort schon ein Webserver, und der muss weg oder umziehen, bevor es weitergeht. Wie du den Schuldigen findest, steht in „Port belegt?“.

Alle Beispielwerte dieser Anleitung auf einen Blick. Ersetze sie im Kopf durch deine eigenen, im Text tauchen sie nur noch auf, ohne erneut erklärt zu werden:

  • IP-Adresse deines Docker-Rechners: 192.168.178.20
  • Ordner für den Proxy: ~/proxy
  • Name des gemeinsamen Docker-Netzes: proxy
  • Beispiel-Dienst: Container uptime-kuma, interner Port 3001
  • Name für den Dienst im Browser: kuma.home.arpa (die Endung home.arpa ist laut RFC 8375 für Heimnetze reserviert, es gibt sie also nirgends im Internet)

Schritt 1: Ein gemeinsames Netz für Proxy und Dienste

Docker sperrt jeden Container in seine eigene kleine Welt. Damit der Proxy einen Dienst überhaupt erreichen kann, brauchen beide ein gemeinsames Netz. Die Doku von Nginx Proxy Manager empfiehlt genau das als bewährte Praxis: ein eigenes Docker-Netz anlegen, Proxy und Dienste hineinhängen, und die Dienste müssen dann keine Ports mehr nach außen veröffentlichen. Der Bonus steht im selben Absatz der Doku: Der Dienstname wird zum Hostnamen. Der Proxy findet Uptime Kuma also unter dem Namen uptime-kuma, ohne dass du eine IP nachschlagen musst.

docker network create proxy
docker network ls | grep proxy

Der zweite Befehl ist die Kontrolle. Er zeigt eine Zeile mit proxy und bridge. Mehr passiert hier nicht, das Netz ist da.

Schritt 2: Nginx Proxy Manager starten

Du legst einen Ordner an und darin eine Datei compose.yaml. Das ist das Rezept, nach dem Docker den Proxy baut. Der Editor nano öffnet die Datei, du fügst den Inhalt ein, speicherst mit Strg+O und Enter und verlässt ihn mit Strg+X.

mkdir -p ~/proxy
cd ~/proxy
nano compose.yaml

Das kommt in die Datei. Es ist das Beispiel aus der offiziellen Setup-Seite, an drei Stellen angepasst: Zeitzone auf Berlin, die Version fest auf 2.15.1, und am Ende das Netz aus Schritt 1.

services:
  app:
    image: 'jc21/nginx-proxy-manager:2.15.1'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
      - '81:81'
    environment:
      TZ: "Europe/Berlin"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt

networks:
  default:
    external: true
    name: proxy

Die Zeilen bedeuten: Port 80 und 443 sind die öffentliche Tür, Port 81 ist die Verwaltungsoberfläche. Die beiden volumes-Zeilen legen Einstellungen und Zertifikate in Unterordner von ~/proxy, damit sie einen Neubau des Containers überleben. Der Block networks hängt den Proxy in das Netz proxy, statt ein eigenes anzulegen.

docker compose up -d
docker compose ps

Der Container heißt nginx-proxy-manager und steht in der Ausgabe von docker compose ps mit Up. Die Setup-Seite warnt, dass der erste Start je nach Hardware eine Minute dauern kann, weil Schlüssel erzeugt und die Datenbank angelegt werden. Danach öffnest du im Browser http://192.168.178.20:81. Kommt dort die Oberfläche von Nginx Proxy Manager, läuft der Proxy.

Wenn er sofort läuft, ist das schön, und trotzdem würde ich einmal in die Logs sehen. Dinge, die beim ersten Mal ohne Murren starten, haben bei mir ein leichtes Glaubwürdigkeitsproblem.

docker compose logs --tail 30

Eine Fehlermeldung, die dort auf Rechnern ohne IPv6 auftaucht, lautet:

Address family not supported by protocol

Die Doku nennt dafür die einfache Lösung: in der compose.yaml unter environment die Zeile DISABLE_IPV6: 'true' ergänzen und den Container mit docker compose up -d neu starten.

Schritt 3: Das erste Konto

Beim ersten Aufruf von http://192.168.178.20:81 zeigt Nginx Proxy Manager keine Anmeldung, sondern ein Formular für den ersten Benutzer (Stand 2.15.x). Trag Name, E-Mail-Adresse und ein Passwort ein und schließ das Formular ab. Danach bist du eingeloggt.

Wenn dein Video oder deine Anleitung noch von admin@example.com und dem Passwort changeme spricht, ist sie älter als deine Installation. Die aktuelle Doku spricht ausdrücklich vom „first user setup screen“, den man nur per Umgebungsvariablen überspringen kann. Ich finde die neue Lösung besser: Ein Standardpasswort, das jeder kennt, hatte nichts an der Tür zu deinem Homelab verloren.

Woran du siehst, dass alles stimmt: Nach dem Login steht das Dashboard mit vier Zählern für Proxy Hosts, Redirection Hosts, Streams und 404 Hosts, alle auf null. Der Proxy weiß noch von keinem Dienst. Das ändern wir jetzt.

Schritt 4: Uptime Kuma hinter den Proxy stellen

Uptime Kuma muss in dasselbe Netz wie der Proxy. Wenn es schon läuft, hängst du den Container nachträglich hinein, ohne ihn neu zu bauen.

docker network connect proxy uptime-kuma
docker network inspect proxy --format '{{range .Containers}}{{.Name}} {{end}}'

Der zweite Befehl listet die Mitglieder des Netzes. Dort stehen jetzt nginx-proxy-manager und uptime-kuma. Fehlt einer, ist er nicht im Netz, und der Proxy wird ihn nicht finden.

Jetzt der Eintrag in der Liste des Proxys, also die Zeile „kuma.home.arpa gehört zu uptime-kuma:3001“:

Oben im Menü Hosts, dann Proxy Hosts, dann rechts Add Proxy Host. Im Reiter Details: bei Domain Names kuma.home.arpa eintragen und mit Enter bestätigen, Scheme auf http, Forward Hostname / IP uptime-kuma, Forward Port 3001. Die Schalter Block Common Exploits und Websockets Support einschalten, dann Save.

Zwei Felder verdienen einen Satz. Scheme http beschreibt den Weg vom Proxy zum Dienst, nicht den vom Browser zum Proxy; Uptime Kuma spricht intern schlichtes HTTP, also steht hier http, auch wenn du später von außen HTTPS nutzt. Websockets Support braucht Uptime Kuma zwingend, sein eigenes Wiki sagt zu Nginx Proxy Manager wörtlich „Please enable WebSockets Support“. Ohne den Schalter lädt die Seite, zeigt aber keine Daten.

Ob der Proxy den Dienst erreicht, prüfst du ohne DNS und ohne Browser. Der Befehl tut so, als hätte jemand kuma.home.arpa eingetippt, und schickt die Anfrage an Port 80 des Proxys:

curl -sI -H "Host: kuma.home.arpa" http://192.168.178.20/

In der ersten Zeile steht HTTP/1.1 200 OK oder eine Weiterleitung mit 302. Beides heißt: Der Proxy hat den Namen erkannt und Uptime Kuma hat geantwortet. Steht dort 502 Bad Gateway, spring zu den Stolpersteinen unten, das ist der Klassiker.

Für den Browser fehlt noch ein Schritt: Dein Heimnetz muss wissen, dass kuma.home.arpa die Adresse 192.168.178.20 meint. Das erledigt ein lokaler DNS-Eintrag, im Router oder besser im Pi-hole, falls du eines betreibst. Wie Pi-hole ins Netz kommt, steht in „Pi-hole mit FritzBox einrichten“. Danach öffnest du http://kuma.home.arpa, und Uptime Kuma erscheint ohne Portnummer in der Adresszeile. Das ist der Moment, für den du das alles gemacht hast. Kurz stolz sein ist erlaubt.

Die ersten Einstellungen

Der Proxy läuft, aber die Standardwerte sind auf „läuft“ optimiert, nicht auf „läuft vernünftig“. Vier Dinge würde ich am selben Abend noch ändern.

Port 81 bleibt im Heimnetz. Die Verwaltungsoberfläche ist die Schaltzentrale für alle deine Türen. Sie darf im Router nie freigegeben werden, auch nicht „nur kurz zum Testen“. Der Standard veröffentlicht sie auf allen Schnittstellen des Rechners, was im Heimnetz in Ordnung ist, aber eben nur dort. Willst du den Port ändern, kennt die Doku die Variable NPM_ADMIN_PORT.

Die Seitentür schließen. Uptime Kuma ist weiter direkt über 192.168.178.20:3001 erreichbar, weil sein Port noch veröffentlicht ist. Der Proxy bringt erst dann Ordnung, wenn er der einzige Weg ist. In der compose.yaml von Uptime Kuma die ports-Zeilen entfernen und den Container mit docker compose up -d neu bauen. Im gemeinsamen Netz findet der Proxy ihn weiterhin, nur der Rest der Welt nicht mehr.

curl -sI --max-time 3 http://192.168.178.20:3001/ || echo "Seitentuer ist zu"

Version festhalten, nicht latest. Die Setup-Seite zeigt 2.15.1, das README zeigt latest. Ich würde die Zahl nehmen. In den Issues liegt der Grund: In Issue #5608 berichtet ein Nutzer, dass Watchtower seinen Proxy über Nacht aktualisiert hat und der Container danach mit „Address already in use“ nicht mehr hochkam; die Ursache blieb im Thread offen. Genau das ist der Punkt: Ein Proxy, der nach einem Update steht, nimmt alle Dienste dahinter mit, und morgens um sieben sucht niemand gern nach der Ursache.

Zwei Ordner sichern. In ~/proxy/data liegen alle Einträge, in ~/proxy/letsencrypt die Zertifikate. Geht der Rechner kaputt, ist mit diesen zwei Ordnern und der compose.yaml alles in fünf Minuten wieder da. Ohne sie tippst du jeden Proxy Host neu. Ja, der Backup-Hinweis kommt in jeder Anleitung, und ja, ich weiß, dass er nervt.

Was hier absichtlich fehlt: echtes HTTPS mit Let's Encrypt. Dafür brauchst du eine eigene Domain, und im reinen Heimnetz geht nur der DNS-Weg, weil die HTTP-Prüfung laut Let's Encrypt zwingend über Port 80 aus dem Internet läuft. Das ist ein eigener Beitrag. Bis dahin würde ich im Heimnetz mit HTTP leben, und sobald der erste Dienst von außen erreichbar sein soll, nicht mehr.

Wo es klemmt: 502 und ein belegter Port 80

502 Bad Gateway, weil „localhost“ im Forward-Feld steht. Das ist die häufigste Falle, und sie ist schon 2020 als Issue #555 dokumentiert. Innerhalb des Proxy-Containers meint 127.0.0.1 den Proxy selbst, nicht deinen Rechner. Im Docker-Forum beschreibt jemand exakt dieses Muster mit Nextcloud und WordPress: Der Proxy versuchte, den Port bei sich selbst zu finden. Die Lösung dort und hier: Container-Name als Hostname, und beide Container in einem Netz.

502, weil der falsche Port drinsteht. Bei ports: "3000:8080" ist 3000 die Nummer für den Rechner und 8080 die im Container. Die Docker-Doku sagt es klar: Zwischen Containern zählt immer der Container-Port. In den Proxy Host gehört also die rechte Zahl, auch wenn du sie noch nie im Browser getippt hast.

502, weil der Dienst nicht im Netz hängt. Der Test mit docker network inspect aus Schritt 4 zeigt es sofort. Ein Ratschlag aus demselben Docker-Forum-Thread bringt es auf den Punkt: Container sind zum Isolieren gebaut, wer mehrere verbinden will, braucht ein Netz.

Der Proxy startet nicht: „bind() to 0.0.0.0:80 failed (98: Address in use)“. So steht es in Issue #834, und der Fall ist immer derselbe: Auf dem Rechner läuft schon etwas auf Port 80, oft ein Webserver, der mit einer anderen Anwendung mitkam. Der Prüfbefehl aus „Was du brauchst“ zeigt den Prozess, der Beitrag zu belegten Ports oben zeigt, wie er weicht.

Braucht ein Homelab mit drei Diensten das wirklich?

Ich würde den Proxy ab dem zweiten Dienst aufsetzen, nicht erst ab dem zehnten. Nicht weil zwei Portnummern schwer zu merken wären, sondern weil jeder Dienst danach nur noch eine Zeile im Proxy ist statt eines eigenen Ports, eines eigenen Zertifikats und einer eigenen Regel im Router. Der Aufwand ist einmalig, der Nutzen wächst mit jedem Container.

Ein Reverse Proxy ist dabei kein Sicherheitszauber. Er macht nichts sicher, was dahinter unsicher ist. Aber er reduziert die Zahl der Türen auf eine, und eine Tür kann man im Blick behalten. Das ist die ehrlichste Zusammenfassung, die ich habe.

Wie viele Dienste laufen bei dir, und wie viele davon rufst du noch mit Portnummer auf? Und falls du schon einen Proxy hast: Nginx Proxy Manager, Caddy oder Traefik, und warum der? Schreib es in die Kommentare, ich lese mit.

Wenn der nächste Container bei dir Pi-hole wird, ist die LXC-Anleitung für Proxmox der passende Anschluss, denn genau dort legst du später die lokalen Namen für deine Dienste an.

Quellen