Skip to main content
Fix Docker "Port Is Already Allocated"

Fix Docker "Port Is Already Allocated"

KU
• 7 min read•Updated •63 views

You run docker run, and it refuses to bind port 8080. Something already owns that port. Here is how to find the holder and get your container up.

Key takeaways

  • Docker's "Bind for 0.0.0.0:8080 failed: port is already allocated" means something already holds that host port, usually another container or a forgotten dev server.
  • Find it with docker ps --filter publish=8080, then sudo ss -ltnp.
  • Stop the holder, or change the left side of -p to a free host port.

Docker's "Bind for 0.0.0.0:8080 failed: port is already allocated" means another container or host process already owns that host port. Find the holder with docker ps --filter publish=8080 (or sudo ss -ltnp | grep :8080), stop it, or publish to a free host port instead, for example -p 8081:80.

You run the container you have run a hundred times, and Docker throws this back:

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

Or the plain kernel version, which shows up when something outside Docker is holding the port:

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

Both say the same thing. With -p 8080:80, Docker binds host port 8080 on every host address (0.0.0.0 and [::]) to forward traffic to the container. If anything already owns 8080, the bind fails and the container never starts.

Note the shape of the mapping while we are here. -p 8080:80 means host 8080 -> container 80. The number on the left is the one that fights over the host. The number on the right lives inside the container and never conflicts with anything on the host. Almost every "port is already allocated" error is about the left number.

First, find who owns the port

There are two suspects: another Docker container, or a regular process on the host. Check Docker first because it is the fast one.

bash.bash
docker ps --filter publish=8080

That lists only containers publishing 8080. If you get a hit, there is your culprit:

code
CONTAINER ID   IMAGE       PORTS                    NAMES
7f9c1a2b3d4e   nginx       0.0.0.0:8080->80/tcp     old-web

Stop it and, if you do not need it, remove it:

bash.bash
docker stop old-web
docker rm old-web

Re-run your container. Done in most cases.

If docker ps --filter publish=8080 comes back empty, the port is held by something that is not a running container. Two possibilities remain: a non-Docker process, or a stopped container that never got cleaned up. Time for the host-level tools.

bash.bash
sudo lsof -i :8080
code
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node    18422 kiril  22u  IPv4  ...    0t0      TCP  *:http-alt (LISTEN)

On boxes without lsof installed, ss does the same thing and is usually already there:

bash.bash
sudo ss -ltnp | grep :8080
code
LISTEN 0  511  0.0.0.0:8080  0.0.0.0:*  users:(("node",pid=18422,fd=22))

There it is: a stray node dev server on PID 18422 that you left running three days ago, the single most common cause I see. On Docker Desktop for Mac, lsof may instead show com.docker.backend, which means a container (possibly in another Compose project or context) owns the port.

Fix it: evict the holder or move your port

Once you know who holds the port, you have two honest options.

Option A: kill the holder. Reasonable when it is a leftover process you actually want gone.

bash.bash
kill 18422
# still there? it ignored SIGTERM, so:
kill -9 18422

Reach for kill -9 only after a plain kill fails to clear it. Give the process a second to shut down before you go nuclear.

Option B: move your container to a free host port. This is the option I reach for most, because whatever is on 8080 is often something I want running too. Change only the host side of the mapping:

bash.bash
docker run -p 8081:80 nginx

Container still listens on 80 internally; you just reach it on localhost:8081 from the host. Nothing inside the app changes. If you do not care which host port you get at all, let Docker pick one:

bash.bash
docker run -p 80 nginx
docker port <container>   # tells you which host port it grabbed

The stopped-container trap

A container that is stopped but not removed keeps its port mapping in its config, and with a restart policy like unless-stopped it grabs the port again whenever the daemon restarts, often before your new container does. docker ps shows nothing because it only lists running containers. You need -a:

bash.bash
docker ps -a --filter publish=8080
code
CONTAINER ID   IMAGE   STATUS                    PORTS   NAMES
c5d6e7f8a9b0   web     Exited (0) 2 hours ago            web-old

Remove it and it can never reclaim the port:

bash.bash
docker rm web-old

If nothing at all shows up in docker ps -a, lsof, or ss and the error persists, the daemon's own port bookkeeping is stale, typically after a crash. sudo systemctl restart docker clears it.

Compose leftovers and double-publishing

Two more that come up constantly.

If you run Docker Compose, an old stack from a previous branch or project may still be up, holding the port. The docker ps filter will show it, but the clean fix is to tear the whole stack down from the project directory:

bash.bash
docker compose down

That stops and removes every service the Compose file defined, which releases their ports in one shot. Beats hunting containers one by one.

The other self-inflicted one: publishing the same host port twice inside a single Compose file or a single docker run. Two services both asking for 8080:80 will fail the moment the second one starts. Grep your Compose file:

bash.bash
grep -n "8080:" docker-compose.yml

If you find two, one of them needs a different host port. This is also where expose versus ports confusion bites. expose only documents that a container listens on a port and makes it reachable to other containers on the same Docker network. It does not bind anything on the host and it never causes this error. Only ports (and -p) publish to the host, and only published ports can collide. If you were reaching for expose to fix an allocation error, you are in the wrong file.

For the broader map of what else goes wrong with containers, see our Docker troubleshooting guide.

Questions people ask

What does "Bind for 0.0.0.0:8080 failed: port is already allocated" mean?

Docker tried to publish host port 8080 on all interfaces and found it taken. The 0.0.0.0 part just means "every IPv4 address on the host". The port number is the left side of your -p flag, so either free that port or choose a different one.

How do I find which container is using a port?

Run docker ps --filter publish=8080, which lists running containers publishing or exposing that port. Add -a to include stopped ones. If neither finds anything, the holder is a regular process: use sudo lsof -i :8080 or sudo ss -ltnp | grep :8080 to get its PID.

Can I bind the container only to localhost to avoid conflicts?

Binding to 127.0.0.1 with -p 127.0.0.1:8080:80 limits who can reach the port, but it still collides with anything already listening on 127.0.0.1:8080 or 0.0.0.0:8080. It is a security choice, not a conflict fix. To avoid conflicts, pick an unused host port.

The call we'd make

Run docker ps --filter publish=8080 first, every time. It answers the question in one line for the majority of cases, and it costs nothing. If it comes back empty, go straight to sudo ss -ltnp | grep :8080 to catch the non-Docker holder, and do not forget docker ps -a for the stopped-container reservation. As for the fix: when the port belongs to something you also want running, remap your container to a free host port and move on. Killing processes to reclaim 8080 is a habit that eventually costs you the wrong process at the wrong time.

Sources

Explore topics:DockerDevOps
React
Share this post
KU

Kiril Urbonas

AI Engineer

553 articles
View all articles by Kiril Urbonas

You might have missed

Evergreen posts worth revisiting.