Docker Compose Ports erklärt
Jeder aus einer README kopierte Compose-Stack nutzt dieselbe Handvoll Ports. So funktionieren Host- vs. Container-Port und ports vs. expose wirklich, warum Multi-Stack-Homelabs kollidieren, und wann ein Reverse Proxy sinnvoll ist.

Docker Compose Ports erklärt
Sie fügen dem Homelab-Host einen dritten Stack hinzu, führen docker compose up -d aus und erhalten Error response from daemon: driver failed programming external connectivity: Bind for 0.0.0.0:8080 failed: port is already allocated. An Ihrer YAML ist nichts falsch. Zwei unabhängige Projekte wollten beide Port 8080 belegen, und nur ein Prozess auf dem Host kann ihn tatsächlich halten.
TL;DR
ports: "8080:80"veröffentlicht einen Container-Port auf dem Host;expose: "80"macht ihn nur für andere Container im selben Compose-Netzwerk erreichbar.- Host-Port-Kollisionen entstehen, weil jeder aus einer README kopierte Stack dieselben naheliegenden Ports verwendet — 80, 443, 8080, 3000.
- Eine Kollision lässt sich auf drei Arten lösen: die Host-Seite ändern, Docker einen freien Port wählen lassen, oder den Port gar nicht erst veröffentlichen, wenn ihn nichts außerhalb von Compose braucht.
- Sobald zwei oder mehr web-basierte Stacks auf einem Host laufen, sollten Sie aufhören, jeden Port einzeln zu veröffentlichen — ein Reverse Proxy auf 80/443 übernimmt das Routing nach Hostnamen.
- Mein eigenes Homelab betreibt neun Compose-Stacks auf einem Host; die Port-Kollision oben ist mir beim Hinzufügen des neunten tatsächlich passiert.
Host-Port vs. Container-Port: Die Links/Rechts-Aufteilung
Jeder Eintrag unter ports: in einer docker-compose.yml folgt dem Schema HOST:CONTAINER:
services:
web:
image: nginx
ports:
- "8080:80" # host:container
Die linke Zahl, 8080, geben Sie im Browser auf der Maschine ein, auf der Docker läuft. Die rechte Zahl, 80, ist das, worauf die Anwendung im Container tatsächlich lauscht — und sie muss sich fast nie ändern, weil sie vom Image vorgegeben ist, nicht von Ihnen. Laut der offiziellen Compose-File-Referenz müssen Sie nur die Host-Seite ändern, um eine Kollision zu vermeiden; die Container-Seite bleibt, was die Anwendung erwartet.
Compose akzeptiert für dieselbe Zuordnung auch eine Langform, nützlich, sobald Sie ein bestimmtes Protokoll oder eine Host-IP benötigen:
ports:
- target: 80
published: 8080
protocol: tcp
host_ip: 127.0.0.1
Note
Eine Bindung an host_ip: 127.0.0.1 statt des Standards 0.0.0.0 macht einen Port nur vom Host selbst aus erreichbar — nützlich für ein Admin-Panel, das Sie immer über Tailscale oder einen SSH-Tunnel ansteuern, nie direkt aus dem Internet.
ports vs. expose: Der tatsächliche Unterschied
expose sieht ähnlich aus, tut aber etwas ganz anderes. Laut derselben Compose-File-Referenz dokumentiert expose lediglich, dass ein Container auf einem Port lauscht, und macht ihn für andere Services im selben Compose-Netzwerk erreichbar — der Host-Netzwerkstack wird dabei nie berührt.
ports: |
expose: |
|
|---|---|---|
| Erreichbar von der Host-Maschine | Ja | Nein |
| Erreichbar aus dem Internet (falls Host öffentlich ist) | Ja, außer durch Firewall blockiert | Nein |
| Erreichbar von anderen Containern im selben Compose-Netzwerk | Ja | Ja |
| Braucht einen freien Host-Port | Ja | Nein |
| Typische Verwendung | Der eine Service, den ein Mensch oder externer Client direkt ansteuert | Eine Datenbank, ein Cache oder eine Backend-API, die nur der eigene Stack aufruft |
Ein Postgres-Container, mit dem nur Ihr App-Container spricht, braucht fast nie ports: — expose: "5432" (oder gar nichts, da Container im selben Netzwerk sich ohnehin über ihren Port erreichen können) hält ihn vollständig vom Host fern, und auch vom Internet, falls dieser Host versehentlich einmal exponiert wird.
Warning
Einen Datenbank-Port aus Gewohnheit mit ports: "5432:5432" zu veröffentlichen, ist die häufigste Art, wie eine Homelab-Postgres- oder Redis-Instanz auf einem Host mit öffentlicher IP am Ende aus dem offenen Internet erreichbar wird. Wenn nichts außerhalb des Compose-Projekts ihn braucht, veröffentlichen Sie ihn nicht.
Warum Multi-Stack-Homelabs auf Ports kollidieren
Diesen Teil lassen die meisten Compose-Tutorials aus, weil sie davon ausgehen, dass Sie einen Stack pro Maschine betreiben. Ein Homelab, das viele unabhängige Projekte auf derselben Proxmox-VM oder Bare-Metal-Box betreibt, hat diesen Luxus nicht — und fast jede Beispiel-docker-compose.yml eines selbst gehosteten Dienstes greift auf dieselbe Handvoll Ports zurück: 80, 443, 8080, 3000, 8000.
KEY-STAT: 9 | Compose-Stacks, die mein eigenes Homelab parallel betreibt, laut meinem Docker-Compose-Self-Hosting-Guide
Der zweite Stack, der 8080 beansprucht, scheitert nicht leise — Docker verweigert den Containerstart komplett, mit dem "port is already allocated"-Fehler aus der Einleitung. Keiner der beiden Stacks ist für sich genommen fehlerhaft; die Kollision entsteht nur, weil beide auf demselben Host laufen.
"Port Is Already Allocated" diagnostizieren
Bevor Sie irgendetwas an der YAML ändern, finden Sie heraus, was den Port tatsächlich belegt:
sudo ss -tlnp | grep :8080 # wer lauscht, und welcher Prozess
sudo lsof -i :8080 # dieselbe Frage, anderes Werkzeug
docker ps --format '{{.Names}}\t{{.Ports}}' | grep 8080 # ist es ein anderes Compose-Projekt?
ss und lsof zeigen, ob der Port überhaupt von einem Container gehalten wird — manchmal ist es ein Dienst, der direkt auf dem Host läuft (ein System-Nginx, ein übrig gebliebener docker run), statt eines anderen Compose-Projekts. docker ps grenzt es, falls es Docker ist, auf den genauen Container und Stack-Namen ein. Stellt sich heraus, dass der Übeltäter ein halb-toter Container aus einem früheren docker compose up ist, der seinen Port nie freigegeben hat, deckt Debugging eines kaputten Docker-Compose-Stacks genau diesen Fehlerfall ab.
Drei Wege, eine Port-Kollision zu beheben
- Die Host-Seite ändern. Die schnellste Lösung: im neueren Stack
ports: "8081:80"statt8080:80eintragen. Die Container-Seite muss sich dafür nie ändern. - Docker einen freien Port wählen lassen. Die Host-Seite weglassen —
ports: "80"— und Compose veröffentlicht den Container-Port 80 auf einem zufälligen freien Host-Port, sichtbar überdocker compose port <service> 80. Gut für Dienste, die Sie nur über einen vom Dashboard generierten Link erreichen. - Gar nicht veröffentlichen. Muss der Port nur von einem anderen Container im selben Compose-Projekt erreichbar sein (eine Datenbank, eine interne API), lassen Sie
ports:ganz weg und verlassen sich auf das Standardnetzwerk von Compose, in dem jeder Service jeden anderen bereits über seinen Service-Namen und Container-Port erreichen kann.
Option 3 ist zugleich die Lösung für die obige Warnung — kein bloßer Workaround für Kollisionen, sondern der korrekte Standardfall für alles, was nicht direkt angesteuert werden soll.
Entscheidung: Wann ein Reverse Proxy sinnvoll ist
Host-Ports einzeln bei jeder Kollision zu ändern, funktioniert bei zwei Stacks problemlos. Ab dem dritten oder vierten web-basierten Dienst skaliert das nicht mehr, weil Sie dann eine wachsende, undokumentierte Liste führen: "Auf welchem Port lief Nextcloud nochmal?" Wie in Docker Compose Netzwerke erklärt beschrieben, isolieren Composes eigene Projekt-Netzwerke die Stacks bereits voneinander — ein Reverse Proxy erlaubt es Ihnen, mit der einzelnen Veröffentlichung jedes Ports aufzuhören und trotzdem alle über die Standard-Ports 80/443 zu erreichen.
| Situation | Ports weiter einzeln veröffentlichen | Reverse Proxy hinzufügen (Caddy / Traefik / nginx-proxy) |
|---|---|---|
| Anzahl web-basierter Stacks auf einem Host | 1 | 2+ |
| Wie Sie Dienste erreichen | host:8080, host:8443, … |
dienst-a.example.com, dienst-b.example.com |
| TLS-Zertifikate | Pro Dienst manuell verwaltet | An einer Stelle, oft automatisch (Caddy, Traefik + Let's Encrypt) |
| Später einen Stack hinzufügen | Einen weiteren freien Port suchen, sich merken | Eine Router-Regel hinzufügen; Port bleibt intern |
Sobald ein Reverse Proxy auf 80/443 sitzt, kann jeder andere Web-Dienst in jedem anderen Compose-Projekt zurück auf reines expose: — keine freien Host-Ports mehr zu suchen, und keine Liste mehr, "was lief nochmal auf 8080".
FAQ
Was ist der Unterschied zwischen ports und expose in Docker Compose?
ports: veröffentlicht einen Container-Port auf der Host-Maschine (und darüber hinaus im Netzwerk, falls der Host erreichbar ist). expose: dokumentiert und erlaubt lediglich den Zugriff von anderen Containern im selben Compose-Netzwerk — der Host-Netzwerkstack wird nie berührt, es wird also kein freier Host-Port benötigt.
Wie behebe ich "bind: address already in use" in Docker Compose?
Finden Sie mit sudo ss -tlnp | grep :<port> oder docker ps heraus, was den Port belegt, und ändern Sie dann entweder die Host-Seite in ports:, lassen Sie die Host-Seite weg, damit Docker einen freien Port zuweist, oder entfernen Sie ports: ganz, falls nichts außerhalb des Compose-Projekts diesen Port braucht.
Können zwei Docker-Compose-Services denselben Port verwenden?
Zwei Services können jeweils auf demselben Container-Port lauschen (z. B. beide auf 80), ohne dass es zu einem Konflikt kommt, weil jeder Container seinen eigenen Netzwerk-Namespace hat. Sie können diesen Port aber nicht beide auf denselben Host-Port veröffentlichen — nur ein Prozess auf dem Host kann einen bestimmten Host-Port gleichzeitig binden.
Muss ich einen Port exponieren, damit Container miteinander kommunizieren können?
Nein. Services im selben Compose-Projekt können sich über ihren Service-Namen und jeden Port, auf den der Container lauscht, bereits über das Standard-Compose-Netzwerk erreichen. expose: ist Dokumentation plus ein Signal für Tools, die es auslesen — für die Container-zu-Container-Kommunikation selbst ist es nicht erforderlich.
Mehr aus Self-Hosting & Privatsphäre

Sie zahlen schon für Proton Mail oder Proton VPN. Jetzt schiebt Proton Ihnen immer wieder Pass unter, den eigenen Passwort-Manager, eingebettet ins selbe Abo — und das Angebot klingt verlockend, bis Sie sich ausmalen müssen, wie Sie Jahre gespeicherter Logins umziehen und was dabei kaputtgeht.

Der zahlenbasierte Entscheidungsrahmen fürs Hinauswachsen aus Docker Compose: Container- und Node-Schwellenwerte, der von fast jedem Guide ausgelassene K3s-Mittelschritt und was ein Umzug wirklich kostet — aus einem Single-Host-Homelab.

Hotel-WLAN muss Ihren Traffic nicht sehen. Ein Tailscale Exit-Node einrichten, damit Handy oder Laptop stattdessen übers Heimnetz routen — die Zwei-Befehle-Einrichtung, die DNS-Leck-Falle und ein echter Kosten-/Geschwindigkeitsvergleich mit einem kommerziellen VPN.
Bleiben Sie auf dem Laufenden
Erhalten Sie die neuesten Artikel direkt in Ihr Postfach. Kein Spam, jederzeit abbestellbar.
Proton Pass: Lohnt sich der Wechsel?
Sie zahlen schon für Proton Mail oder Proton VPN. Jetzt schiebt Proton Ihnen immer wieder Pass unter, den eigenen Passwort-Manager, eingebettet ins selbe Abo — und das Angebot klingt verlockend, bis Sie sich ausmalen müssen, wie Sie Jahre gespeicherter Logins umziehen und was dabei kaputtgeht.
Weiterlesen