← Retour aux tutoriels

Corriger l’erreur Docker « Bind for 0.0.0.0 failed » : port déjà utilisé

dockerdevopsportsdocker-composetroubleshooting

Corriger l’erreur Docker « Bind for 0.0.0.0 failed » : port déjà utilisé

L’erreur Docker du type :

signifie presque toujours la même chose : Docker essaie d’exposer un port sur votre machine (l’hôte), mais ce port est déjà occupé par un autre processus (ou par un autre conteneur Docker), donc le “bind” échoue.

Ce tutoriel explique en profondeur ce que signifie ce bind, comment identifier précisément qui occupe le port, comment corriger durablement (en changeant le mapping, en arrêtant le service concurrent, en ajustant Docker Compose), et comment éviter que cela se reproduise.


1) Comprendre le message : que veut dire « Bind for 0.0.0.0 failed » ?

1.1 Le “bind” côté hôte

Quand vous lancez un conteneur avec un mapping de ports, par exemple :

docker run -p 8080:80 nginx

vous demandez à Docker :

Docker doit donc réserver le port 8080 sur l’hôte. Cela se fait via un “bind” réseau (au niveau du système d’exploitation).

Si le port 8080 est déjà utilisé, Docker ne peut pas l’ouvrir et vous obtenez l’erreur.

1.2 Pourquoi 0.0.0.0 ?

0.0.0.0 signifie “toutes les interfaces réseau” (toutes les IP locales). Docker, par défaut, expose souvent sur toutes les interfaces :

Donc Bind for 0.0.0.0:8080 failed veut dire : “impossible d’écouter sur toutes les interfaces au port 8080”.

1.3 Différence entre port du conteneur et port hôte

Un piège classique :

Le conflit concerne le port hôte (à gauche du :), pas le port interne.

Exemples :


2) Reproduire et reconnaître le problème

2.1 Exemple avec docker run

docker run --name web1 -p 8080:80 nginx
docker run --name web2 -p 8080:80 nginx

Le second échouera avec un message proche de :

Error response from daemon: driver failed programming external connectivity on endpoint web2 (...):
Bind for 0.0.0.0:8080 failed: port is already allocated

2.2 Exemple avec Docker Compose

docker-compose.yml :

services:
  app:
    image: nginx
    ports:
      - "8080:80"

Si un autre service (ou un autre programme) utilise déjà 8080 :

docker compose up

échouera avec un message similaire.


3) Identifier qui utilise le port (Linux)

Sur Linux, vous avez plusieurs outils. L’objectif : obtenir le PID et le nom du processus, ou identifier le conteneur qui a déjà publié ce port.

3.1 Avec ss (recommandé)

sudo ss -ltnp | grep ':8080'

Sortie typique :

LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:* users:(("docker-proxy",pid=12345,fd=4))

Si vous voyez docker-proxy, cela indique souvent qu’un conteneur Docker publie déjà le port.

3.2 Avec lsof

sudo lsof -iTCP:8080 -sTCP:LISTEN -n -P

Exemple :

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
node    27182 you   22u  IPv4  12345      0t0  TCP *:8080 (LISTEN)

Ici, un serveur Node.js écoute déjà sur 8080.

3.3 Avec netstat (ancien mais encore présent)

sudo netstat -tulpn | grep ':8080'

4) Identifier qui utilise le port (macOS)

Sur macOS, lsof est le plus direct :

sudo lsof -nP -iTCP:8080 -sTCP:LISTEN

Vous obtiendrez un PID, puis vous pouvez inspecter :

ps -p <PID> -o pid,ppid,user,command

5) Identifier qui utilise le port (Windows)

5.1 PowerShell : trouver le PID

netstat -ano | findstr :8080

Exemple :

TCP    0.0.0.0:8080     0.0.0.0:0     LISTENING     15432

PID = 15432.

5.2 Identifier le processus

tasklist /fi "PID eq 15432"

Ou :

Get-Process -Id 15432

6) Vérifier si c’est un autre conteneur Docker

Même si ss/lsof montre docker-proxy, vous voulez savoir quel conteneur occupe le port.

6.1 Lister les conteneurs et leurs ports

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

Vous cherchez une ligne du type :

6.2 Filtrer par port

Sur Linux/macOS (shell) :

docker ps --format "{{.Names}} {{.Ports}}" | grep '0.0.0.0:8080'

6.3 Inspecter un conteneur

docker inspect <container_name> --format '{{json .NetworkSettings.Ports}}' | jq

Si vous n’avez pas jq, retirez-le :

docker inspect <container_name> --format '{{json .NetworkSettings.Ports}}'

7) Solutions : choisir la bonne stratégie

Il n’y a pas une seule “bonne” solution. Tout dépend : voulez-vous garder le service existant ? Est-ce un port standard (80/443) ? Est-ce un environnement de dev ? un serveur de prod ?

Voici les solutions les plus courantes, avec commandes réelles.


8) Solution A — Changer le port hôte (le plus simple)

8.1 Avec docker run

Si 8080 est pris, utilisez 8081 :

docker run --name web -p 8081:80 nginx

Vous accédez alors à :

8.2 Avec Docker Compose

Dans docker-compose.yml :

services:
  app:
    image: nginx
    ports:
      - "8081:80"

Puis :

docker compose up -d

8.3 Bonnes pratiques de mapping en développement

En dev, il est courant d’éviter les ports “classiques” (80/443) et de réserver des plages :


9) Solution B — Arrêter le processus qui occupe le port

9.1 Si c’est un service système (Linux)

Exemple : un Nginx local occupe 80/8080.

Vérifier :

sudo systemctl status nginx

Arrêter :

sudo systemctl stop nginx

Désactiver au démarrage (optionnel) :

sudo systemctl disable nginx

9.2 Si c’est un processus “à la main”

Avec PID trouvé via ss/lsof :

kill <PID>

Si le processus ne se termine pas :

kill -9 <PID>

Attention : kill -9 force l’arrêt brutal, à éviter si le processus gère des données.

9.3 Sur macOS

Souvent pareil :

kill <PID>

Ou si c’est un service géré par Homebrew (ex. nginx) :

brew services list
brew services stop nginx

9.4 Sur Windows

Arrêter le processus par PID :

Stop-Process -Id 15432 -Force

Ou via taskkill :

taskkill /PID 15432 /F

10) Solution C — Arrêter le conteneur qui publie déjà le port

Si c’est un autre conteneur Docker :

10.1 Lister et arrêter

docker ps
docker stop <container_name>

10.2 Supprimer (si inutile)

docker rm <container_name>

10.3 Cas Docker Compose

Si le port est pris par un stack Compose :

docker compose down

Si vous avez plusieurs projets, assurez-vous d’être dans le bon répertoire (celui qui contient le docker-compose.yml) ou utilisez -p pour cibler le bon projet.


11) Solution D — N’exposer que sur localhost (réduit les conflits et améliore la sécurité)

Par défaut, -p 8080:80 expose sur toutes les interfaces (0.0.0.0). Vous pouvez restreindre à 127.0.0.1 :

11.1 Avec docker run

docker run --name web -p 127.0.0.1:8080:80 nginx

Cela rend le service accessible uniquement depuis la machine locale.

11.2 Avec Docker Compose

services:
  app:
    image: nginx
    ports:
      - "127.0.0.1:8080:80"

11.3 Pourquoi ça peut “corriger” l’erreur ?

Si un autre service écoute sur 0.0.0.0:8080, vous ne pourrez pas prendre 127.0.0.1:8080 non plus (car 0.0.0.0 couvre toutes les interfaces). En revanche, si le service concurrent écoute uniquement sur une IP spécifique (rare en dev), vous pourriez éviter le conflit. Mais surtout, c’est une bonne pratique : vous évitez d’exposer votre service sur le réseau.


12) Solution E — Laisser Docker choisir un port aléatoire (publication dynamique)

Utile en tests, CI, ou quand vous ne voulez pas gérer les ports.

12.1 Avec docker run -P ou -p 0:...

Publier tous les ports exposés :

docker run --name web -P -d nginx

Voir le port attribué :

docker port web

Ou publier un port spécifique sur un port hôte aléatoire :

docker run --name web -p 0:80 -d nginx
docker port web 80

Sortie typique :

0.0.0.0:49153

Accès :

12.2 Avec Docker Compose

Compose permet de publier sans préciser le port hôte :

services:
  app:
    image: nginx
    ports:
      - "80"

Puis :

docker compose up -d
docker compose ps

Vous verrez le port publié.


13) Solution F — Corriger une confusion fréquente : “EXPOSE” vs “ports”

Dans un Dockerfile, EXPOSE 80 n’ouvre pas le port sur l’hôte. Cela documente le port interne.

C’est -p (ou ports: dans Compose) qui publie.

Donc si vous voyez l’erreur de bind, elle provient d’une publication -p/ports, pas de EXPOSE.


14) Cas particuliers et diagnostics avancés

14.1 Le port semble libre, mais Docker dit qu’il est utilisé

Parfois, un port reste bloqué brièvement (état TIME_WAIT) ou un service redémarre en boucle. Vérifiez l’écoute réelle (LISTEN) :

Linux :

sudo ss -ltnp | grep ':8080'

Si rien n’apparaît mais l’erreur persiste, regardez si Docker a un état incohérent.

Redémarrer le service Docker (Linux systemd) :

sudo systemctl restart docker

Sur macOS/Windows (Docker Desktop), redémarrez Docker Desktop.

14.2 Conflit IPv6

Vous pouvez voir des variantes avec :::8080 (IPv6). Vérifiez :

sudo ss -ltnp | grep -E '(:8080|:::\s*8080)'

Un service peut écouter en IPv6 et occuper aussi IPv4 selon la configuration (dual-stack). Dans ce cas, le conflit est réel.

14.3 Ports privilégiés (<1024) sur Linux

Publier sur 80/443 peut nécessiter des droits particuliers selon le contexte (surtout hors Docker). Avec Docker, c’est généralement géré par le daemon, mais des politiques de sécurité peuvent s’appliquer.

Si votre objectif est juste du dev, préférez :

14.4 UFW/iptables et règles NAT Docker

Même si ce n’est pas la cause principale de “port already allocated”, des règles peuvent perturber l’accès. Pour vérifier les règles Docker :

sudo iptables -t nat -S | grep DOCKER

Ou avec nftables selon la distro. Ici, on diagnostique surtout l’accessibilité, pas l’allocation du port.


15) Exemples concrets : corriger rapidement selon le scénario

Scénario 1 : un serveur web local occupe 8080

  1. Identifier :
sudo lsof -iTCP:8080 -sTCP:LISTEN -n -P
  1. Décider :

Changer le port Docker :

docker run -p 8081:80 nginx

Scénario 2 : un ancien conteneur publie encore 5432 (PostgreSQL)

  1. Trouver le conteneur :
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep 5432
  1. L’arrêter :
docker stop <nom>
  1. Relancer votre stack :
docker compose up -d

Scénario 3 : Docker Compose, plusieurs projets utilisent le même port

Vous avez deux projets qui publient 8080:80. Solution : attribuer des ports distincts :

Projet A :

ports:
  - "8080:80"

Projet B :

ports:
  - "8081:80"

Puis :

docker compose up -d

16) Prévenir l’erreur : recommandations pratiques

16.1 Standardiser vos ports par projet

Documentez un tableau simple :

Évitez que deux stacks publient les mêmes ports.

16.2 Préférer des noms de services et des réseaux internes

Si vos conteneurs communiquent entre eux (app → db), vous n’avez pas besoin d’exposer la base de données sur l’hôte.

Exemple Compose : exposer seulement l’app, pas la DB :

services:
  app:
    image: myapp
    ports:
      - "8080:8080"
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
    # pas de "ports:" ici

Ainsi, aucun risque de conflit sur 5432 avec un PostgreSQL local.

16.3 Utiliser 127.0.0.1: pour les services de dev

Pour éviter d’exposer sur le réseau et réduire les surprises :

ports:
  - "127.0.0.1:8080:80"

16.4 Vérifier avant de lancer

Quand vous savez que vous allez utiliser un port “populaire”, testez rapidement :

Linux/macOS :

sudo ss -ltn | grep ':8080' || echo "Port 8080 libre"

Windows PowerShell :

netstat -ano | findstr :8080

17) Checklist de dépannage rapide (résumé opérationnel)

  1. Lire le port concerné dans l’erreur (ex. 0.0.0.0:8080).
  2. Trouver qui écoute :
    • Linux : sudo ss -ltnp | grep ':8080'
    • macOS : sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
    • Windows : netstat -ano | findstr :8080
  3. Si c’est un conteneur :
    • docker ps --format "table {{.Names}}\t{{.Ports}}"
    • docker stop <nom>
  4. Sinon, si c’est un service local :
    • stop via systemctl, brew services, ou kill PID
  5. Alternative simple : changer le port hôte dans -p / ports:.
  6. Option dev : bind sur 127.0.0.1 ou port aléatoire.

18) Commandes prêtes à copier-coller (par port variable)

Remplacez PORT=8080 par votre port.

Linux

PORT=8080
sudo ss -ltnp | grep ":$PORT" || echo "Aucun LISTEN sur $PORT"
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep "$PORT" || true

macOS

PORT=8080
sudo lsof -nP -iTCP:$PORT -sTCP:LISTEN || echo "Aucun LISTEN sur $PORT"
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep "$PORT" || true

Windows PowerShell

$PORT=8080
netstat -ano | findstr ":$PORT"
docker ps --format "table {{.Names}}\t{{.Ports}}"

19) Conclusion

L’erreur Docker « Bind for 0.0.0.0 failed » n’est pas mystérieuse : vous tentez de publier un port hôte déjà pris. La résolution consiste à :

Si vous indiquez votre OS (Linux/macOS/Windows), le port exact et la commande utilisée (docker run ... ou docker compose ...), je peux proposer une procédure ciblée et un diagnostic plus précis (notamment en cas de conflits IPv6 ou de stacks Compose multiples).