/인프라/Docker 'port is already allocated': a 30-second diagnosis and recovery runbook
Infrastructure웹서버트러블슈팅서버에러해결

Docker 'port is already allocated': a 30-second diagnosis and recovery runbook

A practical runbook to diagnose Docker's 'Bind for 0.0.0.0:XXXX failed: port is already allocated' error in 30 seconds and recover with copy-paste commands. Precisely fixes zombie docker-proxy processes and leftover container port occupancy

Docker 'port is already allocated': a 30-second diagnosis and recovery runbook

docker compose up and this error again

If you run several stacks locally, you'll hit this several times a day.

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

Many 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 stateLikely cause30-second identification hint
docker ps shows another container publishing 8080① Another container already holds the portA 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 containerOld 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 portdocker-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 bootProcess 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.

Bash
# ① Identify a "live" container publishing this port
docker ps --filter publish=8080

If a container name appears → cause ①. Use the name from the NAMES column in the recovery step.

Bash
# ② Include stopped containers (detect leftover Exited state)
docker ps -a --filter publish=8080

If a name is listed with Exited (...)cause ②. It hasn't been rm'd yet, so the port reservation remains.

Bash
# ③ Who is LISTENing at the kernel socket level + PID
sudo ss -ltnp | grep :8080

If 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 ④.

Bash
# ④ Check zombie docker-proxy list only (search by that port argument)
ps aux | grep '[d]ocker-proxy' | grep 8080

If this process is alive with no container, it's a confirmed zombie. You'll see a -host-port 8080 argument.

Bash
# ⑤ Check leftover network endpoints (endpoint remains with no container)
docker network inspect bridge | grep -A4 Containers

If 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:

Bash
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.

Bash
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.

Bash
# 1) Clean leftover containers/networks the normal way
docker compose down --remove-orphans
docker container prune -f
docker network prune -f

After 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.

Bash
# 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-proxy also severs port mappings of other healthy containers. Kill only the single PID for that port confirmed via ss. Use kill -9 only 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.

Bash
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)

Bash
sudo systemctl restart docker

🚨 Warning box: This command restarts every container on the host. Containers without a restart policy 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 zombie docker-proxy still isn't cleaned by the kill method 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.

YAML
services:
  web:
    image: nginx
    ports:
      - "8081:8080"   # Change only the left (host) side to 8081; leave the container-internal port as-is
Bash
docker compose up -d

Preventing recurrence: never get stuck on this error again

1) Avoid fixed host ports; use a range or random

YAML
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:

Bash
docker compose port web 8080

2) Detect zombie/unhealthy state early with a healthcheck

YAML
services:
  web:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      timeout: 3s
      retries: 3

3) 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-stopped on services that should keep running.
  • Force docker compose down -v --remove-orphans into the CI pipeline teardown step to block leftovers at the source.
YAML
services:
  web:
    restart: unless-stopped

Habituating 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-orphansdocker container prune -fdocker 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.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·
관련 공식 문서Docker 공식 문서

Comments

Be the first to comment.