Zum Inhalt

Docker-Ports absichern: Dienste nur im Heimnetz oder auf localhost freigeben

Veröffentlicht am 15. Oktober 2026 · Geschätzte Lesezeit: 6 Minuten

Jeder mit ports: oder -p veröffentlichte Port in Docker ist standardmäßig auf allen Netzwerkschnittstellen des Hosts erreichbar – auch dann, wenn du den Dienst nur lokal oder im Heimnetz nutzen willst.[1] Ein Datenbank-Container, ein Admin-Interface oder eine Entwicklungsumgebung gehört nicht ins Internet, sondern nur auf den localhost oder in dein vertrautes LAN. Mit einer gezielten IP-Adresse vor dem Portmapping schränkst du die Reichweite sofort ein. Plane etwa 20 bis 35 Minuten für Bestandsaufnahme, Änderung eines Compose-Stacks und Zugriffstest von einem zweiten Gerät ein. Das Video How to Publish Docker Container Ports zeigt ergänzend die Grundlagen von -p und -P.[6]

Voraussetzungen

  • Ein Linux-Server mit Docker und Docker Compose (Plugin)
  • Terminal-Zugriff mit sudo-Rechten
  • Eine vorhandene compose.yaml mit mindestens einem Dienst, der Ports veröffentlicht
  • Die feste LAN-IP deines Docker-Hosts (DHCP-Reservierung oder statisch)
  • Ein zweites Gerät im selben Netz zum Testen

1. Aktuelle Port-Veröffentlichungen prüfen

Verschaffe dir zunächst einen Überblick, welche Ports deine laufenden Container gerade freigeben. Führe den Befehl auf dem Docker-Server aus:

docker ps --format 'table {{.Names}}\t{{.Ports}}'

Kritische Anzeigen sind beispielsweise:

0.0.0.0:8080->80/tcp
[::]:8080->80/tcp

0.0.0.0 und [::] bedeuten IPv4- beziehungsweise IPv6-Veröffentlichung auf allen Schnittstellen – der Dienst ist potenziell aus dem gesamten Netz und (wenn keine Firewall greift) aus dem Internet erreichbar. Nur 127.0.0.1 oder die konkrete LAN-IP sind sichere Anzeigen. Wie Port-Veröffentlichung grundsätzlich funktioniert, erklärt Docker in seiner Einsteiger-Einführung.[4]

2. Feste LAN-IP des Docker-Hosts ermitteln

Du brauchst die Adresse, unter der dein Server im Heimnetz erreichbar ist. Verwende nicht 0.0.0.0 oder localhost für einen Dienst, der von anderen Geräten im LAN erreichbar sein soll.

hostname -I

Hat der Server mehrere Schnittstellen (WLAN, VPN, VLAN), notiere die Adresse des physikalischen LAN-Anschlusses. Sie beginnt meist mit 192.168., 10. oder 172.16..

Für einen Dienst, den nur der Host selbst erreichen darf, verwendest du später 127.0.0.1. Für das Heimnetz verwendest du die ermittelte LAN-IP (z. B. 192.168.1.77).

3. Compose-Datei sichern

Wechsle in den Ordner deiner Anwendung. Ersetze <app-ordner> durch den vollständigen Pfad, in dem deine compose.yaml liegt:

cd <app-ordner>

Erstelle vor jeder Änderung eine Sicherungskopie:

cp compose.yaml compose.yaml.bak

Falls du mehrere Compose-Dateien (Overrides, Include) verwendest, sichere auch diese.

4. Ports auf localhost oder LAN-IP begrenzen

Öffne deine compose.yaml und ergänze vor dem ersten Doppelpunkt im ports:-Eintrag die Zieladresse.[1][4] Ersetze <vorhandenes-image> durch das Image, das dein Dienst bereits verwendet. Das folgende Beispiel zeigt drei Varianten. Wähle die passende für deinen Dienst:

services:
  zieldienst:
    image: <vorhandenes-image>
    ports:
      # Nur localhost (nur der Host selbst erreicht den Dienst)
      - "127.0.0.1:8080:80"
      # Nur Heimnetz (Geräte im LAN unter der Server-IP)
      - "192.168.1.77:8080:80"
      # IPv6-Loopback (nur Host, Adresse ::1)
      - "[::1]:8080:80"

Die Beispielwerte bedeuten:

  • 127.0.0.1:8080:80 bindet den Host-Port 8080 ausschließlich an die IPv4-Loopback-Schnittstelle. Nur Prozesse auf dem Docker-Host selbst können den Dienst über http://127.0.0.1:8080/ erreichen.[1]
  • 192.168.1.77:8080:80 bindet den Host-Port 8080 an die LAN-IP 192.168.1.77. Geräte im Heimnetz erreichen den Dienst über http://192.168.1.77:8080/.
  • [::1]:8080:80 bindet an IPv6-Loopback. Dein Dienst kann dann nur vom Host selbst über die Adresse [::1] erreicht werden.[1] Achte darauf, auch die IPv4- oder IPv6-Variante deiner gewünschten Reichweite zu setzen.

Docker-Version vor 28.0.0

Docker warnt, dass in Versionen vor 28.0.0 Hosts im selben Layer-2-Segment (also am selben Switch) Ports erreichen können, die auf 127.0.0.1 veröffentlicht wurden.[1] Prüfe deine Docker-Version mit docker version. Wenn du eine ältere Version einsetzt, verwende zusätzlich eine Firewall-Regel oder aktualisiere Docker.

Portangaben in Anführungszeichen setzen

YAML interpretiert 127.0.0.1:8080:80 ohne Anführungszeichen als Zahl oder andere Objekte. Setze jeden Port-Eintrag daher immer als Zeichenkette in doppelten oder einfachen Anführungszeichen.

5. Container neu starten

Wende die Änderung an. Docker Compose erkennt die geänderte ports-Angabe nur bei einem Neustart mit --force-recreate. Ersetze <DIENSTNAME> durch den Namen des Dienstes aus deiner compose.yaml (der Schlüssel direkt unter services:):

docker compose up -d --force-recreate <DIENSTNAME>

Prüfe anschließend, ob der Container läuft:

docker compose ps

6. IPv6-Veröffentlichung prüfen

Docker veröffentlicht Ports standardmäßig sowohl auf IPv4 als auch auf IPv6.[1] Wenn du nur 127.0.0.1:8080:80 setzt, kann der Dienst zusätzlich über [::]:8080 (IPv6-all-interfaces) erreichbar sein, falls kein separates IPv6-Loopback-Mapping existiert. Prüfe deshalb explizit:

docker ps --format 'table {{.Names}}\t{{.Ports}}'

Erwartet werden Adressen wie 127.0.0.1:8080->80/tcp oder 192.168.1.77:8080->80/tcp, nicht [::]:8080->80/tcp. Zeigt Docker weiterhin eine IPv6-all-interfaces-Adresse, ergänze einen expliziten IPv6-Eintrag in der compose.yaml:

    ports:
      - "127.0.0.1:8080:80"
      - "[::1]:8080:80"

7. Zugriff vom Host und von einem zweiten Gerät testen

Führe diese Tests auf dem Docker-Host aus:

curl --fail --show-error http://127.0.0.1:8080/

Schlägt der Test fehl, ist der Dienst entweder nicht erreichbar oder das Portmapping wurde nicht korrekt übernommen. Prüfe die Docker-Logs.

Teste von einem zweiten Gerät im Heimnetz (Handy, Notebook):

curl --connect-timeout 5 http://192.168.1.77:8080/

Erwartung bei localhost-Bindung: Der Zugriff scheitert (Connection refused oder Timeout) – der Dienst ist nur lokal erreichbar.
Erwartung bei LAN-Bindung: Der Zugriff funktioniert – der Dienst ist im Heimnetz sichtbar.

Firewall schützt nicht automatisch vor Docker-Ports

UFW, iptables und firewalld blockieren standardmäßig nicht von Docker veröffentlichte Ports, weil Docker seine eigenen Firewall-Regeln direkt in der NAT-Tabelle setzt.[3] Praxistests bestätigen: Selbst mit aktivem ufw deny bleiben Docker-Ports aus dem Netz erreichbar.[5] Verlasse dich nicht auf ufw deny allein, um einen Docker-Container-Port abzusichern. Die Bindung an eine bestimmte IP (127.0.0.1 oder die LAN-IP) ist der sichere Weg, die Reichweite zu begrenzen.

Backup und Rückweg

Stelle die ursprüngliche Compose-Datei wieder her, falls ein Dienst nach der Änderung nicht startet. Ersetze <app-ordner> und <DIENSTNAME> wie zuvor erklärt:

cd <app-ordner>
cp compose.yaml.bak compose.yaml
docker compose config --quiet
docker compose up -d --force-recreate <DIENSTNAME>

Die compose.yaml.bak enthält keine Nutzdaten. Datenbanken und zustandsbehaftete Volumes müssen separat gesichert sein.

Risiken

  • Falsche oder dynamische LAN-IP: Trägst du eine IP ein, die der Server nicht besitzt (weil DHCP die Adresse geändert hat), startet der Container nicht oder bindet an die falsche Schnittstelle. Verwende eine DHCP-Reservierung oder eine statische IP.
  • Port nicht mehr erreichbar: Wenn der Dienst von anderen Containern über den Host-Port und nicht über das interne Docker-Netz angesprochen wird, kann die Bindung an localhost diese Verbindung unterbrechen.
  • network_mode: host: Dieser Modus umgeht das Portmapping vollständig. Der Container teilt sich alle Netzwerkschnittstellen des Hosts. Dann hilft nur eine Host-Firewall.

Typische Fehler

  • Host-Port (8080) und Container-Port (80) vertauscht. Die Reihenfolge ist immer <host-ip>:<host-port>:<container-port>. Ersetze <host-ip> durch die Zieladresse, <host-port> durch den Port auf dem Host und <container-port> durch den Port im Container.
  • localhost von einem anderen Rechner getestet. localhost bezeichnet immer den testenden Rechner, nicht den Server.
  • Port entfernt, obwohl ein anderes Programm auf dem Host denselben Port benötigt.
  • Änderung gespeichert, Container aber nicht neu gestartet (--force-recreate).
  • Nur IPv4 geprüft, IPv6-Veröffentlichung übersehen.
  • Zweite Compose-Datei oder Override überschreibt die Ports.

Fertig

Deine Docker-Container-Ports sind jetzt auf localhost oder eine gezielte LAN-IP beschränkt und nicht mehr unbeabsichtigt auf allen Schnittstellen erreichbar.

Kurze Funktionsprüfung:

  1. Auf dem Server muss der lokal gebundene Dienst antworten. Ersetze die Beispielportangabe 8080 durch den tatsächlichen Host-Port aus dem Portmapping:
curl --fail --show-error http://127.0.0.1:8080/

→ Hinweis: Ersetzt du den Port nicht, testest du nur den Beispielport 8080. Ein reiner Verbindungstest unabhängig vom HTTP-Protokoll funktioniert auch mit nc -vz 127.0.0.1 8080 (Port dort ebenfalls anpassen).

  1. Von einem zweiten Gerät muss der Zugriff auf die LAN-IP je nach gewähltem Modus funktionieren oder scheitern.

  2. docker ps --format 'table {{.Names}}\t{{.Ports}}' zeigt die erwartete IP-Adresse, nicht 0.0.0.0 oder [::].

  3. Prüfe die Container-Logs auf Bindungsfehler. Ersetze <DIENSTNAME> durch deinen Dienstnamen:

docker compose logs --tail=50 <DIENSTNAME>

Sources

[1] https://docs.docker.com/engine/network/port-publishing — Docker: Port publishing and mapping [3] https://docs.docker.com/engine/network/packet-filtering-firewalls — Docker: Packet filtering and firewalls [4] https://docs.docker.com/get-started/docker-concepts/running-containers/publishing-ports — Docker: Publishing ports (beginner) [5] https://www.virtua.cloud/learn/en/tutorials/docker-ufw-firewall-fix-vps — Virtua Cloud: Docker, UFW and localhost bindings [6] https://www.youtube.com/watch?v=CKMfDNCigzM — Video: How to Publish Docker Container Ports