Du willst nur eben einen neuen Container starten — Vaultwarden, Immich, irgendwas Schönes fürs Homelab — und Docker grätscht rein: Bind for 0.0.0.0:80 failed: port is already allocated. Oder die Geschwister-Variante address already in use. Willkommen bei einem der meistgegoogelten Probleme überhaupt. Die gute Nachricht: Der Fall ist in ein paar Minuten gelöst, wenn du weißt, welche zwei Befehle du fragen musst. Genau das machen wir jetzt — systematisch, vom Symptom bis zum Fix.

Kurz gesagt: Am Ende weißt du, wie du mit ss -tulpn jeden belegten Port einem Prozess oder Container zuordnest — und kennst drei saubere Wege, ihn freizugeben. Dauer: rund 10 Minuten. Schwierigkeit: Einsteiger, ein Terminal reicht.
Schaubild: Port belegt — in vier Schritten zur Lösung: Meldung lesen, Lauscher finden, Einordnen, Freigeben
Der ganze Weg auf einen Blick: von der Fehlermeldung zum freien Port.

Was du brauchst

  • Einen Linux-Rechner oder -Server (Debian, Ubuntu, Raspberry Pi OS — egal)
  • sudo-Rechte und ein Terminal
  • Docker nur, falls dein Problem aus einem Container kommt — die Diagnose selbst funktioniert auch ohne

Schritt 1: Die Fehlermeldung lesen — sie verrät schon die halbe Lösung

Bevor du wild Container neustartest: Docker sagt dir ziemlich genau, was los ist. Es gibt zwei Varianten dieser Meldung, und sie bedeuten unterschiedliche Dinge.

Variante eins:

Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use

Übersetzt: Ein Prozess auf dem Host selbst hält den Port fest — ein vorinstallierter Webserver, ein Systemdienst, irgendwas außerhalb von Docker.

Variante zwei:

Bind for 0.0.0.0:80 failed: port is already allocated

Übersetzt: Ein anderer Docker-Container hat sich den Port schon geschnappt. Oft ein Überbleibsel von einem früheren Experiment, das still im Hintergrund weiterläuft.

Port? Die IP-Adresse ist die Hausanschrift deines Servers, der Port die Zimmernummer. Port 80 ist zum Beispiel das Zimmer für unverschlüsselte Webseiten, 443 das für verschlüsselte. Und pro Zimmer darf genau ein Dienst wohnen — will ein zweiter einziehen, bekommst du exakt diese Fehlermeldung.
Neuer Container→ will Port 80 →Port 80← wohnt schon hier ←Alt-Prozess

Schritt 2: Herausfinden, wer auf dem Port lauscht

Jetzt wird verhört. Das Werkzeug dafür heißt ss und ist auf so gut wie jedem aktuellen Linux vorinstalliert:

sudo ss -tulpn | grep :80

Die Buchstabensuppe dahinter ist schnell erklärt: -t zeigt TCP, -u UDP, -l nur lauschende Ports, -p den zugehörigen Prozess und -n Portnummern statt Dienstnamen. Das sudo ist kein Deko-Element: Ohne Root-Rechte bleibt die Prozess-Spalte bei fremden Prozessen einfach leer, und du verhörst eine Wand.

Die Ausgabe sieht dann etwa so aus:

tcp  LISTEN  0  511  0.0.0.0:80  0.0.0.0:*  users:(("nginx",pid=1234,fd=6))

Da steht der Name des Schuldigen samt Prozess-ID. Falls du lieber lsof magst, geht auch das:

sudo lsof -i :80

Beide Befehle beantworten dieselbe Frage. Such dir einen aus und merk ihn dir — du wirst ihn wieder brauchen.

Schritt 3: Den Schuldigen einordnen

Jetzt kommt es darauf an, was in der Prozess-Spalte steht.

Fall A — ein normaler Dienst wie nginx, apache2 oder smbd: Das ist ein Programm direkt auf dem Host. Mit systemctl status nginx siehst du, ob es als Systemdienst läuft und seit wann.

Fall B — da steht docker-proxy: Dann ist es ein Container. Welcher genau, verrät dir diese Zeile:

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

Das listet alle laufenden Container mit ihren Port-Zuordnungen, etwa 0.0.0.0:80->2368/tcp. Der Container, bei dem dein Port vor dem Pfeil steht, ist dein Kandidat.

Schritt 4: Den Port freigeben — drei saubere Wege

Weg 1: Den Alt-Dienst stoppen. Der Klassiker ist ein Apache oder nginx, der bei der Server-Installation mitkam und den nie jemand bestellt hat. Wenn du ihn nicht brauchst:

sudo systemctl stop apache2
sudo systemctl disable apache2

stop beendet den Dienst sofort, disable sorgt dafür, dass er nach dem nächsten Neustart nicht wieder aus dem Gebüsch springt. Vorher kurz nachdenken: Läuft da wirklich nichts drüber, was du brauchst?

Weg 2: Deinem neuen Dienst einen anderen Host-Port geben. Wenn der bisherige Bewohner bleiben soll, zieht der Neue einfach in ein anderes Zimmer. In der Compose-Datei:

services:
  meindienst:
    ports:
      - "8081:80"

Danach erreichst du den Dienst unter http://server-ip:8081.

Port-Mapping? Bei "8081:80" ist links der Host-Port (die Haustür, an der Besucher klingeln) und rechts der Container-Port (die Wohnungstür innen drin). Bei einem Konflikt änderst du immer nur die linke Seite. Die rechte gehört der Anwendung im Container — änderst du die, klingelt Docker an einer Tür, hinter der niemand wohnt.

Weg 3: Den Zombie-Container abräumen. Wenn ein vergessener Container den Port hält und du ihn nicht mehr brauchst:

docker stop alter-container
docker rm alter-container

Danach startet dein neuer Stack ohne Murren.

Schritt 5: Der Spezialfall Port 53

Ein Kapitel für sich, weil er so viele erwischt: Wer Pi-hole oder AdGuard Home installieren will, scheitert auf Ubuntu und vielen anderen modernen Distributionen zuverlässig an Port 53. Der Übeltäter heißt systemd-resolved — ein Systemdienst, der auf der Adresse 127.0.0.53 einen kleinen DNS-Vermittler betreibt, den sogenannten Stub-Listener. Nützlich für den Alltag, im Weg, sobald du selbst DNS-Server spielen willst.

Der offiziell von Pi-hole dokumentierte Fix in drei Zeilen:

sudo sh -c 'mkdir -p /etc/systemd/resolved.conf.d && printf "[Resolve]\nDNSStubListener=no\n" | tee /etc/systemd/resolved.conf.d/no-stub.conf'
sudo sh -c 'rm /etc/resolv.conf && ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf'
sudo systemctl restart systemd-resolved

Zeile eins legt eine Konfigurationsdatei an, die den Stub-Listener abschaltet. Zeile zwei biegt /etc/resolv.conf auf die Datei um, die systemd-resolved automatisch mit den echten DNS-Servern deines Netzwerks pflegt — sonst weiß dein Server danach selbst nicht mehr, wie man Namen auflöst. Zeile drei startet den Dienst neu, damit alles greift. Wichtig: Das machst du nur, wenn du auf dieser Maschine wirklich einen eigenen DNS-Dienst betreiben willst. Für alle anderen Port-Konflikte gilt weiter Schritt 4.

Häufige Stolpersteine

ss ohne sudo ausgeführt: Der Port taucht auf, aber die Prozess-Spalte ist leer — und du rätst ins Blaue. Einfach mit sudo wiederholen.

docker-proxy gekillt: Bitte nicht. Das ist kein eigenständiges Programm, sondern Dockers Weiterleitungshelfer für den Container. Stopp stattdessen den Container, der dahintersteckt (Schritt 3, Fall B).

Die falsche Seite des Mappings geändert: Aus "8081:80" wurde "8080:81", und plötzlich antwortet gar nichts mehr. Merkregel aus der Klartext-Box: links Haustür, rechts Wohnungstür — nur links anfassen.

Dienst mit kill -9 abgeschossen: systemd startet seine Schützlinge brav neu, der Port ist zwei Sekunden später wieder belegt. Systemdienste beendest du mit systemctl stop, sonst spielst du Whack-a-Mole.

Fazit

Ein belegter Port sieht nach Drama aus, ist aber eines der dankbarsten Probleme im Homelab: Die Fehlermeldung sagt dir, in welcher Ecke du suchen musst, und ss -tulpn liefert den Namen frei Haus. Meine Einschätzung: In neun von zehn Fällen ist der Schuldige ein vergessener Container oder ein vorinstallierter Webserver, und der Fix dauert keine fünf Minuten. Den Befehl einmal ins Muskelgedächtnis übernehmen — danach hat diese Fehlermeldung ihren Schrecken dauerhaft verloren.

Welcher Port-Klassiker hat dich schon Nerven gekostet — der ungefragte Apache, ein Zombie-Container oder doch der Endgegner Port 53? Und räumst du alte Container konsequent ab, oder sammelt sich bei dir auch eine kleine Geisterstadt? Schreib's in die Kommentare.

One more thing … wenn dein Stack wieder läuft und du künftig sofort merken willst, sobald ein Dienst schwächelt: In unserer Anleitung Uptime Kuma mit Docker installieren baust du dir in einer Viertelstunde einen Wachdienst, der dich anstupst, bevor es jemand anderes merkt.

Quellen