docker compose up and this error again
If you run several stacks locally, you'll hit this several times a day.
Error response from daemon: driver failed programming external connectivity
on endpoint web (a1b2c3...): Bind for 0.0.0.0:8080 failed: port is already allocatedMany people go down the wrong path hunting for a host application process with lsof -i :8080. This error's failure point is different from a classic EADDRINUSE where nginx or node on the host is the culprit. This post focuses on cases where the Docker layer — another container, a leftover container, a zombie docker-proxy, or a Docker network endpoint — is holding the port, not a regular host OS application.
- Scope: Docker Engine 20.10+, Docker Compose v2 (
docker compose, no hyphen), Linux hosts (Ubuntu/RHEL family). Differences for macOS/Windows Docker Desktop are covered separately in the FAQ. - Goal: error text → match the cause → copy-paste diagnosis commands → copy-paste recovery commands, restarting within 30 seconds along this flow.
If you're in a hurry, find your symptom in the matching table below and jump straight to the diagnosis and recovery blocks.
Cause matching table: error text → identify one of 4 causes in 30 seconds
8080 is an example port. Substitute the port that's actually colliding.
| Symptom / observed state | Likely cause | 30-second identification hint |
|---|---|---|
docker ps shows another container publishing 8080 | ① Another container already holds the port | A name shows up in docker ps --filter publish=8080 |
You just started the stack, but an old container is still Exited/Up | ② Reran without down; leftover previous container | Old container exists in docker ps -a --filter publish=8080 |
Nothing in docker ps -a but the error persists. ss shows docker-proxy holding it | ③ Zombie docker-proxy holding the port | docker-proxy PID in sudo ss -ltnp | grep :8080 |
8080 occupied from boot, unrelated to Docker. Not docker-proxy | ④ systemd or another service claimed it at boot | Process in ss output is a non-Docker service name |
① and ② are common and easy. ③ is the core of this post (the error persists even after you've deleted every container). ④ is not actually a Docker problem, so you need to stop that service.
Copy-paste diagnosis commands: who is holding the port
Run these top to bottom; the cause will narrow itself.
# ① Identify a "live" container publishing this port
docker ps --filter publish=8080If a container name appears → cause ①. Use the name from the NAMES column in the recovery step.
# ② Include stopped containers (detect leftover Exited state)
docker ps -a --filter publish=8080If a name is listed with Exited (...) → cause ②. It hasn't been rm'd yet, so the port reservation remains.
# ③ Who is LISTENing at the kernel socket level + PID
sudo ss -ltnp | grep :8080If you see docker-proxy like users:(("docker-proxy",pid=12345,...)) but no container in ①② above → cause ③ (zombie). If the process name is not Docker → cause ④.
# ④ Check zombie docker-proxy list only (search by that port argument)
ps aux | grep '[d]ocker-proxy' | grep 8080If this process is alive with no container, it's a confirmed zombie. You'll see a -host-port 8080 argument.
# ⑤ Check leftover network endpoints (endpoint remains with no container)
docker network inspect bridge | grep -A4 ContainersIf a dead container ID remains under Containers, you also need to clean up the network.
Copy-paste recovery commands: exact release per situation
Once the cause is identified, run only that block. Dangerous commands are called out separately with warnings below.
Cause ① Another container is occupying the port
Confirm by name that it's a container you're actually allowed to take down, then:
docker stop <name> && docker rm <name>If you need to keep the other stack running, don't kill that container — changing your own port is safer (see the port-change workaround at the bottom).
Cause ② Leftover previous container — this is the most common
When you reran without docker compose down and orphan containers remain, --remove-orphans is the key.
docker compose down --remove-orphans
docker compose up -d--remove-orphans also cleans leftover containers that are no longer defined in the current compose file. Especially needed after you edit the compose file and service names change.
Cause ③ Zombie docker-proxy — error even after deleting containers
Try the proper sequence first. This usually fixes it.
# 1) Clean leftover containers/networks the normal way
docker compose down --remove-orphans
docker container prune -f
docker network prune -fAfter cleanup, rerun sudo ss -ltnp | grep :8080 and check whether docker-proxy is gone. If it's gone, you can up immediately.
If docker-proxy is still holding the port, it's a real zombie. Only then kill the PID directly.
# 2) Kill the exact docker-proxy PID confirmed during diagnosis
sudo ss -ltnp | grep :8080 # Reconfirm PID (e.g. pid=12345)
sudo kill 12345 # SIGTERM first
# If it doesn't die
sudo kill -9 12345 # SIGKILL only as a last resort⚠️ Caution: Killing every process by name with
pkill docker-proxyalso severs port mappings of other healthy containers. Kill only the single PID for that port confirmed viass. Usekill -9only when a clean shutdown (SIGTERM) doesn't work.
Cause ④ systemd or another service claimed it first
This isn't a Docker problem, so stop that service or change the Docker port.
sudo ss -ltnp | grep :8080 # Confirm process name (e.g. nginx.service)
sudo systemctl stop nginx # Stop + disable if needed🚨 Last resort — restart the Docker daemon (large side effects)
sudo systemctl restart docker🚨 Warning box: This command restarts every container on the host. Containers without a
restartpolicy may not come back, and other running stacks (DBs, queues, etc.) will all drop at once. Use this only as a last resort when the zombiedocker-proxystill isn't cleaned by thekillmethod above, after checking the blast radius on other stacks.
Immediate workaround — change only the port and start now
If you need it running now and don't have time to analyze the cause, changing the host port in compose is the fastest path.
services:
web:
image: nginx
ports:
- "8081:8080" # Change only the left (host) side to 8081; leave the container-internal port as-isdocker compose up -dPreventing recurrence: never get stuck on this error again
1) Avoid fixed host ports; use a range or random
services:
web:
ports:
- "8080-8090:8080" # If 8080 is taken, the next free port is assigned automatically
api:
ports:
- "8080" # Omit host port → random port (check with docker port <c>)Confirm the actual mapping for a random port with:
docker compose port web 80802) Detect zombie/unhealthy state early with a healthcheck
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
timeout: 3s
retries: 33) Standardize shutdown habits and policies
- Always take a stack down with
docker compose down --remove-orphans— don't just stop containers. - Explicitly set
restart: unless-stoppedon services that should keep running. - Force
docker compose down -v --remove-orphansinto the CI pipeline teardown step to block leftovers at the source.
services:
web:
restart: unless-stoppedHabituating just these three essentially eliminates causes ② and ③.
References: official docs
The primary source for the behavior, settings, and errors covered here is the following official documentation. Check version-specific options and exact behavior there.
FAQ
Q1. I docker rm'd every container and still get port is already allocated.
A. A leftover docker-proxy process or Docker network endpoint. Confirm the docker-proxy PID with sudo ss -ltnp | grep :PORT and clean endpoints with docker network prune -f. If it still remains, sudo kill only that port's docker-proxy PID (do not pkill by name).
Q2. How do I fix this without systemctl restart docker?
A. Usually yes. Clean in this order: docker compose down --remove-orphans → docker container prune -f → docker network prune -f. The zombie docker-proxy often disappears with that. Restarting the daemon restarts every other container too, so it's a last resort.
Q3. Does the difference between Bind for 0.0.0.0 and 127.0.0.1 affect the cause?
A. The bind address only changes which interface the port is opened on; the occupancy cause itself is the same. Mapping to 127.0.0.1:8080 is localhost-only, so it may not collide with 8080 on external/other interfaces. Specifying "127.0.0.1:8080:8080" in compose can shrink the collision surface.
Q4. Do the same methods work on macOS/Windows Docker Desktop?
A. Container cleanup (docker compose down --remove-orphans, prune) and the port-change workaround work the same. Docker Desktop runs Docker on a Linux VM, though, so you generally cannot see and kill a docker-proxy PID from host ss/ps. If you suspect a zombie, clean containers and networks, then Restart Docker Desktop itself.
Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
Comments
Be the first to comment.