Docker Error Guide: 'port is already allocated' Container Port Bind Failures
Fix Docker 'port is already allocated' and 'address already in use' bind errors: free conflicting containers, host processes, stale docker-proxy, and remap ports.
- #docker
- #troubleshooting
- #errors
- #networking
Exact Error Message
When you docker run -p 8080:80 ... or docker compose up and something already owns the host port, the daemon refuses to start the container and prints:
docker: 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.
A closely related variant comes straight from the kernel when the host socket is taken by a non-Docker process:
Error response from daemon: driver failed programming external connectivity on endpoint web: failed to bind host port for 0.0.0.0:8080:172.17.0.2:80/tcp: address already in use
The container is created but never transitions to a running state, so a follow-up docker ps -a shows it as Created or Exited.
What It Means
Docker publishes a container port to the host by binding a socket on the host’s network namespace — either through docker-proxy (the userland proxy) or directly via an iptables/nftables DNAT rule. To bind 0.0.0.0:8080, the host must have that (address, port, protocol) tuple free. port is already allocated is Docker’s own bookkeeping saying it already handed 8080/tcp to another container endpoint. address already in use (EADDRINUSE) is the kernel saying a socket — Docker’s or anyone else’s — already holds it.
The distinction matters: the first usually means another container (or a stale docker-proxy) owns the port; the second often means a plain host process (nginx, a dev server, systemd socket) is listening. Either way the new container cannot publish to that host port until the holder is released or you map to a different one.
It is worth being precise about what “the port” means here. A binding is a tuple of address, port, and protocol — 0.0.0.0:8080/tcp is a different reservation from 0.0.0.0:8080/udp, and 127.0.0.1:8080 does not conflict with 192.168.1.10:8080. When you write -p 8080:80, Docker expands the host side to 0.0.0.0:8080/tcp, the broadest possible binding, which is why two such mappings always collide even if you intended them for different interfaces. Pinning the host side explicitly (-p 127.0.0.1:8080:80) narrows the reservation and can let two containers coexist on the same numeric port across different addresses. The conflict is always evaluated on the host network namespace, never inside the container, so the container-side port (the :80 half) is irrelevant to this error.
Common Causes
- Another running container already publishes the port. Two
-p 8080:...mappings on the same host port can never coexist. - A stale/exited container still holds the reservation. A container that crashed without clean teardown can leave the allocation registered.
- A lingering
docker-proxyprocess. After an unclean daemon stop, adocker-proxyfor the old container can keep the host socket bound. - Restart race.
restart: alwaysor a fastdocker compose down && upcan race a still-shutting-down container that hasn’t freed the port. - Duplicate
-pflags. The same host port mapped twice in onerunor two services in a compose file colliding. - A host service on the port. nginx, Apache, a systemd-managed daemon, or a local dev server already listening on
8080.
The first three causes are Docker’s own state being out of sync, and the fix is usually to clear a container or restart the daemon. The last three are external — another mapping, a race, or a non-Docker listener — and require either changing your mapping or stopping the other holder. The diagnostic step below tells you which family you are in: if docker ps shows a container on the port, it is Docker’s; if only ss/lsof shows it, it is a host process or an orphaned docker-proxy.
How to Reproduce the Error
Start one container that publishes 8080, then start a second on the same host port:
docker run -d --name web1 -p 8080:80 nginx:alpine
docker run -d --name web2 -p 8080:80 nginx:alpine
The second command fails immediately with Bind for 0.0.0.0:8080 failed: port is already allocated. To reproduce the kernel variant, start a host listener first, then try to publish over it:
python3 -m http.server 8080 &
docker run -d -p 8080:80 nginx:alpine
This yields address already in use, because a non-Docker process owns the socket.
Diagnostic Commands
Find which container (if any) already publishes the port:
docker ps --format 'table {{.Names}}\t{{.Ports}}' | grep 8080
docker port web1
If no container claims it, look at the host’s listening sockets — this reveals both docker-proxy and plain processes:
sudo ss -ltnp 'sport = :8080'
sudo lsof -i :8080
LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:* users:(("docker-proxy",pid=4412,fd=4))
A docker-proxy with no matching running container is a stale process. Inspect Docker’s own view and recent lifecycle events:
docker network inspect bridge | grep -A3 -i ports
docker events --since 10m --filter event=start --filter event=die
If you suspect the daemon’s internal allocation table is out of sync, check the journal:
sudo journalctl -u docker --since "15 min ago" | grep -i 'port\|bind\|allocated'
Step-by-Step Resolution
-
Identify the holder. Run
docker psfiltered on the port; if a container owns it, decide whether to stop it or remap the new one.docker stop web1 # frees 8080 if web1 legitimately should yield it -
Clear a stale/exited container. Remove the dead container that still holds the reservation:
docker rm -f $(docker ps -aq --filter status=exited) -
Kill a lingering
docker-proxy. Ifss/lsofshows adocker-proxywith no live container, it is orphaned. Restarting the daemon clears these safely:sudo systemctl restart docker -
Stop a conflicting host service. If the holder is nginx/systemd rather than Docker, stop or reconfigure it:
sudo systemctl stop nginx -
Remap to a free host port if the holder must keep running. Change only the host side of the mapping:
docker run -d -p 8081:80 nginx:alpine -
Fix duplicate compose mappings. Ensure no two services share a host port, and avoid mapping the same host port twice in one
run.
After the holder is released or the mapping changed, re-run the container and confirm with docker ps that it reaches Up.
A note on the restart race specifically: if a container with restart: always keeps grabbing the port milliseconds before your new one, the holder will not appear in a single docker ps snapshot reliably. Watch the lifecycle with docker events while you redeploy, or stop the restart-looping container explicitly (docker update --restart=no <name> && docker stop <name>) before bringing up the replacement, so the reservation is held by exactly one container at a time.
How to Prevent the Issue
- Reserve a distinct host port per service and document the allocation; treat host ports as a shared, finite resource.
- Prefer letting Docker assign an ephemeral host port (
-p 80or-p ::80) for throwaway containers, then read the chosen port withdocker port. - Use
docker compose down(not juststop) beforeupto guarantee the previous network and port reservations are torn down before the new ones bind. - Avoid binding services on the host to the same ports you publish from containers; pick a clear split (e.g., host apps on 80/443, containers on 8000+).
- After daemon crashes, run
sudo systemctl restart dockerto clear orphaneddocker-proxyprocesses before redeploying.
Related Docker Errors
- Docker Error Guide: ‘Error initializing network controller’ — when the daemon’s bridge/NAT setup itself fails, port publishing breaks before any allocation conflict.
- Browse more Docker troubleshooting guides for registry, DNS, and storage errors.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.