Docker-Netzwerke verstehen: bridge, internes DNS & das proxy-Netz
Warum deklariert jedes App-Rezept ein proxy-Netz? Dieser Guide erklärt Docker-Netzwerke, das interne DNS und Container-Isolation an echten Befehlen.
Inhaltsverzeichnis
networks: [proxy] – dieser Halbsatz taucht in fast jedem App-Rezept der Serverküche auf, meist unkommentiert. Höchste Zeit, ihn einmal zentral zu erklären. Danach verstehst du, wie Container sich finden, warum manche kein Internet brauchen und wie Traefik überhaupt an sie herankommt.
Was bauen wir?
Kein neuer Dienst, sondern das Netzwerk-Modell hinter jedem Docker-Stack. Am Ende weißt du, warum du eigene Netzwerke anlegen solltest statt das Standard-bridge, wie Container sich per Name statt IP erreichen (das interne DNS), was ein internal-Netz ohne Internetzugang bringt und warum das gemeinsame proxy-Netz der Trick ist, mit dem Traefik jede App erreicht. Alle Ausgaben stammen von einem echten Debian 13-Server mit Docker 29.
Voraussetzungen
- Ein Server mit installiertem Docker und Grundwissen zu Docker Compose
- Root- oder
docker-Gruppen-Zugang (siehe Benutzer & Rechte) - Kein zusätzliches Paket – alles bringt Docker mit
VPS 1000 G12
4 vCore · 8 GB RAM · 256 GB NVMe
ab 10,36 €/Monat
Ein kleiner VPS reicht, um mehrere Container-Netze durchzuspielen.
💶 5 € Gutschein für netcup-Neukunden:36nc17844976032
(nur Neukunden, keine Domains)
Schritt für Schritt
Schritt 1: Was schon da ist
Nach der Installation bringt Docker drei Netzwerke mit:
docker network lsNETWORK ID NAME DRIVER SCOPE
9d087537e327 bridge bridge local
b622109fef73 host host local
e12e562ad7f6 none null localbridge– das Standard-Netz. Container ohne explizite Netzangabe landen hier. Es funktioniert, hat aber einen entscheidenden Haken (Schritt 3).host– der Container teilt sich den Netzwerk-Stack des Hosts direkt (kein Isolations-Layer, keine Port-Zuordnung). Nur für Sonderfälle.none– gar kein Netzwerk. Für Container, die bewusst offline sein sollen.
Für eigene Stacks nutzt du keines davon direkt, sondern legst eigene Netzwerke an. Warum, zeigt Schritt 3.
Schritt 2: Ein eigenes Netzwerk anlegen
docker network create demo-netDocker erstellt ein bridge-Netz und vergibt automatisch ein Subnetz:
docker network inspect demo-net --format 'name={{.Name}} driver={{.Driver}} subnet={{range .IPAM.Config}}{{.Subnet}}{{end}}'name=demo-net driver=bridge subnet=172.20.0.0/16Jeder Container in diesem Netz bekommt eine IP aus 172.20.0.0/16. Aber mit IPs willst du gar nicht arbeiten – sie ändern sich bei jedem Neustart. Der eigentliche Gewinn ist etwas anderes.
Schritt 3: Das interne DNS – Container per Name finden
Starte zwei Container in demo-net: einen Webserver und einen Client.
docker run -d --name web --network demo-net nginx:1.29-alpine
docker run -d --name client --network demo-net alpine:3.20 sleep 600Jetzt der entscheidende Test – der Client erreicht den Webserver über seinen Namen:
docker exec client ping -c 2 webPING web (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.171 ms
64 bytes from 172.20.0.2: seq=1 ttl=64 time=0.095 msDocker löst den Containernamen web automatisch auf die richtige IP auf. Das gilt auch für HTTP:
docker exec client wget -qO- http://web/<title>Welcome to nginx!</title>Genau deshalb steht in Compose-Dateien DB_HOST=db statt einer IP: db ist der Servicename, und Docker macht daraus die richtige Adresse. Der Vergleich mit dem Standard-bridge zeigt, warum du es meidest – dort gibt es keine Namensauflösung:
docker run -d --name legacy1 nginx:1.29-alpine
docker run --rm alpine:3.20 ping -c 1 legacy1ping: bad address 'legacy1'Compose macht das automatisch
docker compose up legt für den Stack automatisch ein eigenes benanntes Netz an (z. B. meineapp_default) – mit funktionierendem DNS. Deshalb erreichen sich die Services eines Compose-Files immer per Name, ohne dass du etwas tust. Das Standard-bridge betrifft nur Container, die du von Hand mit docker run ohne --network startest.Schritt 4: Segmentieren – Datenbank ohne Internet
Nicht jeder Container braucht jeden anderen zu sehen. Eine Datenbank soll nur von ihrer App erreichbar sein und braucht selbst kein Internet. Dafür gibt es internal-Netze:
docker network create --internal demo-interninternal: true kappt die Route nach draußen. Der Beweis:
docker run --rm --network demo-intern alpine:3.20 \
sh -c "wget -qT4 -O- http://example.com >/dev/null 2>&1 && echo REACHED || echo BLOCKED"BLOCKEDDas ist ein starkes Sicherheitsmuster: Selbst wenn ein Angreifer die Datenbank kompromittiert, kann sie keine Verbindung nach außen aufbauen (kein Nachladen von Schadcode, kein Datenabfluss). Ein typischer Stack nutzt deshalb zwei Netze: ein internal-Netz zwischen App und Datenbank, und das öffentliche proxy-Netz nur zwischen App und Traefik.
Schritt 5: Das proxy-Netz – wie Traefik jede App erreicht
Jetzt der meistkopierte Halbsatz des Katalogs. Traefik läuft in einem eigenen Container und muss mit jeder App reden, um deren Anfragen weiterzuleiten. Container reden aber nur miteinander, wenn sie im selben Netz sind. Die Lösung: ein gemeinsames, dauerhaftes Netz namens proxy.
docker network inspect proxy --format 'name={{.Name}} driver={{.Driver}} subnet={{range .IPAM.Config}}{{.Subnet}}{{end}} internal={{.Internal}}'name=proxy driver=bridge subnet=172.19.0.0/16 internal=falseTraefik hängt dauerhaft in diesem Netz. Jede neue App tritt ihm bei – in Compose so:
services:
meineapp:
image: beispiel/app:1.0
networks:
- proxy # damit Traefik die App erreicht
- intern # private Verbindung zur Datenbank
labels:
- "traefik.enable=true"
# ... die Router-/Service-Labels
networks:
proxy:
external: true # von Traefik angelegt, NICHT neu erstellen
intern:
internal: trueZwei Dinge sind hier zentral: external: true sagt Docker „dieses Netz existiert schon, häng dich nur an“ – legst du es versehentlich neu an, landet die App in einem anderen proxy-Netz als Traefik und ist über die Domain nicht erreichbar (der Klassiker aus dem 502-Troubleshooting). Und über das zweite Netz intern erreicht die App ihre Datenbank, ohne dass diese je im öffentlichen Netz hängt.
Schritt 6: Ports veröffentlichen – nur wo nötig
In allen bisherigen Schritten reden Container untereinander, ohne einen einzigen Port zu veröffentlichen. Ein Port muss nur dann nach außen, wenn der Host oder das Internet direkt zugreifen soll:
docker run -d --name pub -p 8099:80 nginx:1.29-alpine
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8099/200-p 8099:80 bindet Host-Port 8099 auf Container-Port 80. In Compose ist das ports: ["8099:80"]. Der wichtige Unterschied zu expose: expose macht einen Port nur für andere Container sichtbar (netzintern), ports öffnet ihn zum Host.
Hinter Traefik keine App-Ports veröffentlichen
ports:. Traefik erreicht sie über das proxy-Netz; ein zusätzlich veröffentlichter Port umginge Traefik und damit HTTPS, Middlewares und Firewall-Logik. Veröffentliche nur die Ports von Traefik selbst (80/443). Alles andere bleibt netzintern.Wenn es nicht funktioniert
Container erreicht anderen nicht per Name (bad address). Beide hängen nicht im selben benannten Netz, oder einer nutzt das Standard-bridge (kein DNS). Prüfe mit docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' CONTAINER, in welchen Netzen ein Container hängt.
Traefik gibt 502 Bad Gateway. Fast immer sind Traefik und die App in verschiedenen proxy-Netzen, weil das Netz doppelt angelegt wurde. external: true im Compose sicherstellen und mit docker network inspect proxy prüfen, ob beide Container gelistet sind.
network proxy not found beim up. Das externe Netz existiert noch nicht. Einmalig anlegen: docker network create proxy (bzw. Traefik zuerst starten, das es erstellt).
Datenbank hat trotz internal Internet. Sie hängt zusätzlich in einem nicht-internen Netz (z. B. proxy). Ein Container hat die Summe der Zugriffe aller seiner Netze – die DB gehört nur ins interne Netz, nie ins proxy-Netz.
Zwei Stacks kollidieren beim Subnetz. Docker vergibt 172.x-Bereiche automatisch, aber bei vielen Netzen kann der Pool knapp werden (could not find an available, non-overlapping IPv4 address pool). Ungenutzte Netze aufräumen: docker network prune.
Wartung & Backups
- Netzwerke brauchen kein Backup – sie werden aus der Compose-Datei jederzeit neu erzeugt. Wichtig ist also, dass deine
compose.yamlund dienetworks:-Deklarationen im Backup liegen, nicht der Netz-Zustand selbst. - Verwaiste Netze aufräumen. Nach vielen Tests sammeln sich ungenutzte Netze an.
docker network lszeigt sie,docker network pruneentfernt alle ohne angehängte Container. Das dauerhafteproxy-Netz bleibt dabei erhalten, solange Traefik läuft. - Das
proxy-Netz ist Infrastruktur. Behandle es wie Traefik selbst: einmal anlegen, dann in Ruhe lassen. Es aus Versehen zu löschen (network prunebei gestopptem Traefik) zwingt dich, alle Apps neu zu verbinden. Mehr zum sauberen Aufräumen steht in Docker-Stack aktuell halten.
Feedback per E-Mail: feedback@serverkueche.de
Das könnte dir auch schmecken

Die eigene Website mit Hugo hosten – wie die Serverküche selbst
Statische Website mit Hugo bauen und im Docker-Container hinter Traefik ausliefern – schnell, sicher, ohne Datenbank. …

AdGuard Home: netzwerkweiter Werbe- und Tracking-Blocker
AdGuard Home mit Docker aufsetzen: ein eigener DNS-Server, der Werbung, Tracker und Schadseiten für alle Geräte blockt – …

Forgejo: der eigene Git-Server hinter Traefik
Forgejo mit Docker & Traefik aufsetzen: eigener Git-Server mit HTTPS, Repos per Web-UI, Klonen über HTTPS und SSH – die …