Docker-Netzwerke und Container-IPs
Docker-Netzwerke und Container-IPs — Konfiguration und Fallstricke
Dieser Artikel erklärt wie Docker IP-Adressen an Container vergibt, warum das nach einem Neustart oder Restore zu Problemen führen kann, und wie man die Konfiguration dauerhaft stabil hält.
Er richtet sich an alle die Nextcloud, Collabora, Caddy oder ähnliche Dienste in Docker betreiben und sich fragen warum nach einem Neustart plötzlich nichts mehr funktioniert.
Wie Docker IPs vergibt
Docker verwaltet ein internes virtuelles Netzwerk. Jeder Container bekommt beim
Start automatisch eine IP-Adresse aus dem konfigurierten Subnetz — standardmäßig
aus 172.17.0.0/16 oder einem selbst definierten Bereich.
Die Vergabe ist dynamisch: Docker vergibt IPs in der Reihenfolge in der
Container starten. .2 geht an den ersten Container, .3
an den zweiten, und so weiter.
Das Problem entsteht nach einem Neustart oder Restore: Container starten in anderer Reihenfolge, bekommen andere IPs — und alle Konfigurationen die auf feste IPs angewiesen sind, zeigen ins Leere.
Dynamische IP — das stille Problem
# Vor dem Neustart: nextcloud → 172.18.0.10 collabora → 172.18.0.4 caddy → 172.18.0.6 # Nach dem Neustart (andere Startreihenfolge): nextcloud → 172.18.0.7 ← verschoben collabora → 172.18.0.4 ← zufällig gleich caddy → 172.18.0.3 ← verschoben
Wenn extra_hosts auf die alte Nextcloud-IP zeigt, schlägt WOPI
stillschweigend fehl — kein offensichtlicher Fehler, nur keine Funktion.
Gepinnte IPs — die Lösung
Mit ipv4_address in der docker-compose.yml bekommt ein
Container immer dieselbe IP — unabhängig von der Startreihenfolge:
<syntaxhighlight lang="yaml"> services:
nextcloud:
networks:
mein-netzwerk:
ipv4_address: 172.18.0.20
caddy:
networks:
mein-netzwerk:
ipv4_address: 172.18.0.6
networks:
mein-netzwerk: external: true
</syntaxhighlight>
Docker reserviert diese IPs dauerhaft — kein anderer Container kann sie belegen.
Welche Container müssen gepinnt werden?
Nicht jeder Container braucht eine feste IP. Gepinnt werden müssen nur Container
die als Ziel in extra_hosts eines anderen Containers erscheinen:
| Container | Gepinnt? | Grund |
|---|---|---|
| Caddy | ja | Nextcloud zeigt per extra_hosts auf Caddy
|
| Nextcloud | ja | Collabora zeigt per extra_hosts auf Nextcloud. Caddy-Firewall-Regel prüft Nextcloud-IP.
|
| Collabora | nein | Caddy spricht Collabora über Docker-DNS-Namen an (collabora:9980), nicht über IP
|
| Datenbank | nein | Wird nur über Docker-DNS-Namen angesprochen |
| Redis/Cache | nein | Wird nur über Docker-DNS-Namen angesprochen |
Faustregel: Wer in einem extra_hosts-Eintrag als IP steht, muss
gepinnt sein. Wer nur über seinen Container-Namen angesprochen wird, kann dynamisch
bleiben.
extra_hosts — wann und warum
extra_hosts schreibt Einträge direkt in die /etc/hosts
des Containers. Das ist nötig wenn ein Container eine Domain intern auflösen soll,
die extern auf eine andere IP zeigt — das klassische
Hairpinning-Problem.
<syntaxhighlight lang="yaml"> services:
nextcloud:
extra_hosts:
# Collabora ist intern über Caddy erreichbar, nicht über die externe IP
- "collabora.beispiel.de:172.18.0.6"
collabora:
extra_hosts:
# Nextcloud ist intern direkt erreichbar
- "nextcloud.beispiel.de:172.18.0.20"
</syntaxhighlight>
Warum nicht einfach DNS?
DNS würde die externe IP zurückgeben — der Container würde den Umweg über den Router nehmen, der Traffic käme von außen zurück (Hairpinning), und der Resolver würde je nach Router-Konfiguration die Verbindung abbrechen.
extra_hosts umgeht DNS komplett: /etc/hosts wird
vor DNS abgefragt — vor dem Router, vor dem VPN, vor allem anderen.
getent vs. nslookup — warum der Unterschied wichtig ist
Der verlässlichste Test ob extra_hosts korrekt greift:
<syntaxhighlight lang="bash"> docker exec nextcloud getent hosts collabora.beispiel.de </syntaxhighlight>
Warum getent statt nslookup?
| getent hosts | nslookup / dig | |
|---|---|---|
Fragt /etc/hosts |
ja | nein |
Fragt extra_hosts |
ja | nein |
| Fragt DNS | ja | ja |
| Zeigt was der Container wirklich sieht | ja | nein |
getent folgt der NSS-Reihenfolge (/etc/nsswitch.conf) —
genau wie das Betriebssystem selbst. nslookup fragt nur DNS und
ignoriert alle lokalen Overrides. Ein grünes nslookup bedeutet also
nicht dass extra_hosts funktioniert.
Die NSS-Reihenfolge
Auf einem typischen Linux-System:
hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns
In einem Docker-Container:
hosts: files dns
In beiden Fällen: files (also /etc/hosts) kommt zuerst.
Wer dort steht, gewinnt — unabhängig von DNS, VPN oder Router.
IP-Konfiguration dokumentieren
Eine gepflegte Übersicht verhindert Verwirrung nach Neustarts oder bei neuen Containern die zufällig eine reservierte IP belegen würden.
Empfohlenes Format in der eigenen Dokumentation:
| Container | IP | Gepinnt | Grund |
|---|---|---|---|
| caddy | 172.18.0.6 | ja | Ziel in Nextcloud extra_hosts |
| nextcloud | 172.18.0.20 | ja | Ziel in Collabora extra_hosts; Caddy-Regel prüft diese IP |
| collabora | dynamisch | nein | Nur über DNS-Namen angesprochen |
| nc-db | dynamisch | nein | Nur über DNS-Namen angesprochen |
| nc-redis | dynamisch | nein | Nur über DNS-Namen angesprochen |
Wichtig: Die Tabelle aktuell halten wenn neue Container hinzukommen — ein
neuer Container der dynamisch startet kann eine reservierte IP nicht belegen,
solange die Pinning-Konfiguration in der compose-Datei steht. Aber ein neuer
Container der selbst als Ziel in extra_hosts erscheinen soll,
muss sofort gepinnt werden.
Backup-Restore-Checkliste
Nach jedem Backup-Restore in der Reihenfolge abarbeiten:
1. IP-Verteilung prüfen
<syntaxhighlight lang="bash"> docker network inspect NETZWERKNAME | grep -E "Name|IPv4" </syntaxhighlight>
Alle gepinnten Container müssen ihre festen IPs haben.
2. DNS-Auflösung in den Containern prüfen
<syntaxhighlight lang="bash"> docker exec nextcloud getent hosts collabora.beispiel.de docker exec collabora getent hosts nextcloud.beispiel.de </syntaxhighlight>
Beide müssen interne IPs zurückgeben — nie die externe öffentliche IP.
Erscheint eine externe IP: extra_hosts greift nicht — die IP in
der docker-compose.yml ist veraltet.
3. Caddy neu starten — nicht nur reload
<syntaxhighlight lang="bash"> docker restart caddy </syntaxhighlight>
caddy reload übernimmt eine neue Konfiguration manchmal nicht
vollständig. Nach einem Restore immer restart verwenden.
4. Collabora-Erreichbarkeit aus Nextcloud prüfen
<syntaxhighlight lang="bash"> docker exec nextcloud curl -sk -o /dev/null -w "%{http_code}" \
https://collabora.beispiel.de/hosting/discovery
</syntaxhighlight>
Erwartetes Ergebnis: 200
403→ Caddy-Regel blockiert. IP inextra_hostsfalsch,
oder Caddy hat alten Stand geladen → Schritt 3 wiederholen.
- Leere Antwort → Nextcloud erreicht Collabora gar nicht →
extra_hosts prüfen (Schritt 2).
5. WOPI-Allowlist prüfen
<syntaxhighlight lang="bash"> docker exec nextcloud occ config:app:get richdocuments wopi_allowlist </syntaxhighlight>
Erwartetes Ergebnis: Das interne Docker-Subnetz, z.B. 172.18.0.0/16
Falls veraltet oder fehlend:
<syntaxhighlight lang="bash"> docker exec nextcloud occ config:app:set richdocuments wopi_allowlist \
--value="172.18.0.0/16"
</syntaxhighlight>
Das gesamte Subnetz statt einer einzelnen IP — damit ist die Allowlist unabhängig von IP-Verschiebungen einzelner Container.
6. Collabora-Konfiguration aktivieren
<syntaxhighlight lang="bash"> docker exec nextcloud occ richdocuments:activate-config </syntaxhighlight>
Erwartetes Ergebnis:
✓ Fetched /hosting/discovery endpoint ✓ Valid mimetype response ✓ Valid capabilities entry ✓ Detected WOPI server: Collabora Online ...
7. Funktionstest — echtes Dokument öffnen
Den Admin-Test in den Nextcloud-Einstellungen nicht als alleinigen Test
verwenden — er läuft vom Browser aus und bekommt deshalb manchmal 403
auch wenn alles korrekt konfiguriert ist.
Echter Test: Eine .docx oder .odt Datei direkt
in Nextcloud öffnen. Wenn das Dokument im Collabora-Editor erscheint, funktioniert
alles.
Häufige Fehlerquellen
| Symptom | Ursache | Fix |
|---|---|---|
403 bei WOPI |
extra_hosts zeigt auf falsche IP |
IP in docker-compose.yml korrigieren, Container neu starten
|
| Leere curl-Antwort | Nextcloud erreicht Caddy nicht intern | getent hosts prüfen, extra_hosts korrigieren
|
200 aber Dokument öffnet nicht |
Nextcloud-Cache veraltet | occ richdocuments:activate-config ausführen
|
| Admin-Test rot, Dokumente gehen | Browser-Referer fehlt | Normal — Admin-Test ist kein verlässlicher Test |
caddy reload hat nichts geändert |
Caddy cached alte Konfiguration | docker restart caddy statt caddy reload
|
| IP-Konflikt beim Container-Start | Anderer Container hat gepinnte IP belegt | docker network inspect → Schuldigen finden → stoppen, neu starten
|
Siehe auch
- Hairpin-NAT – Collabora und Nextcloud hinter Caddy — das Grundproblem das
extra_hostslöst - Caddy – Konzepte und Konfiguration — Reverse Proxy, Matcher, Firewall-Regeln
- Webserver, Reverse Proxy und Container – wie die Schichten zusammenspielen
Entstanden aus einem Debugging-Marathon um 1 Uhr nachts. Möge er anderen erspart bleiben.
