KhueApps
Home/DevOps/Fix Docker “Ports are not available: listen tcp 0.0.0.0:PORT”

Fix Docker “Ports are not available: listen tcp 0.0.0.0:PORT”

Last updated: October 06, 2025

What this error means

Docker tried to publish a container port on your host (0.0.0.0:PORT), but another process or container is already listening there. You must either free the port or choose a different mapping.

Common message:

  • Ports are not available: listen tcp 0.0.0.0:PORT: bind: address already in use

Applies to Linux, macOS, and Windows/WSL2 (Docker Desktop).

Quickstart (most cases)

  1. Identify who is using the port
  • Linux/macOS:
    • sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
    • or: sudo ss -ltnp | grep :8080
  • Windows PowerShell (Admin):
    • Get-NetTCPConnection -LocalPort 8080 -State Listen | Select OwningProcess,LocalAddress,LocalPort
    • Get-Process -Id <PID>
  1. Stop the listener
  • Linux/macOS: sudo kill -9 <PID> or sudo fuser -k 8080/tcp
  • Windows: Stop-Process -Id <PID> -Force
  • If it’s a service (e.g., nginx, IIS), stop/disable the service.
  1. Retry your container
  • docker compose up -d

If the port must remain in use, change your host port mapping instead (for example, map 8081:80).

Minimal Working Example

Create a Compose file that publishes a container port.

docker-compose.yml:

version: "3.8"
services:
  web:
    image: nginx:stable-alpine
    ports:
      - "8080:80"  # host:container

Run:

docker compose up -d

If something is already listening on 8080, you will see the bind error. Free 8080 or change the mapping to a free port, e.g. "8081:80", then rerun.

Step-by-step diagnosis and fix

  1. Check if another container already publishes the port
  • List containers publishing a specific port:
docker ps --filter "publish=8080"
  • Stop/remove the conflicting container:
docker stop <container>
docker rm <container>
  1. Find host processes using the port
  • Linux/macOS:
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
# or
sudo ss -ltnp | grep :8080
  • Windows (PowerShell as Administrator):
Get-NetTCPConnection -LocalPort 8080 -State Listen | Select-Object OwningProcess,LocalAddress,LocalPort
Get-Process -Id <PID>
  1. Free the port
  • Linux/macOS:
sudo fuser -k 8080/tcp  # kill by port
# or
sudo kill -9 <PID>
  • Windows:
Stop-Process -Id <PID> -Force

If the process restarts automatically, disable or stop the service instead (systemd, launchd, Windows Services).

  1. Change your mapping if you cannot free the port
  • docker run examples:
# Bind only to loopback
docker run -d -p 127.0.0.1:8081:80 nginx:stable-alpine
# Use a random host port
docker run -d -p :80 nginx:stable-alpine     # host port chosen automatically
  • Compose examples (ports section):
# Bind to a specific host IP and port
ports:
  - "127.0.0.1:8081:80"
# Let Docker choose a random host port
ports:
  - "127.0.0.1::80"
  1. Verify
docker compose ps
curl -I http://127.0.0.1:8081  # adjust to your mapping

Windows/WSL2 and Docker Desktop specifics

  • Check Windows services that commonly occupy ports (e.g., IIS uses 80/443, SQL Server, Web Deployment Service, etc.). Stop them if not needed.
  • Reserved/excluded port ranges can block binds even if no process is visible:
netsh interface ipv4 show excludedportrange protocol=tcp

Pick a port outside excluded ranges. Avoid ephemeral dynamic ranges too:

netsh interface ipv4 show dynamicport tcp
  • If running Docker Desktop with WSL2 backend, a Windows process (com.docker.backend) forwards ports. Conflicts still follow the same rules: free the port on Windows, not just inside WSL.
  • If a security product or VPN binds to many ports, prefer binding to 127.0.0.1 instead of 0.0.0.0, or choose a different host port.

Alternatives and best practices

  • Bind to localhost when external access is unnecessary:
ports:
  - "127.0.0.1:8080:80"
  • Use a reverse proxy to reduce the number of published ports. Publish only the proxy’s ports; connect internal services via a Docker network.
  • Prefer dynamic host ports for local development to avoid conflicts:
ports:
  - "127.0.0.1::80"   # random host port for container port 80
  • For Linux-only performance and fewer moving parts, consider host networking (not available on Docker Desktop for Mac/Windows):
docker run --network host nginx:stable-alpine

Pitfalls

  • Killing the wrong PID: Always confirm the owning process before stopping it.
  • Auto-restarting services: systemd, launchd, or Windows Services may respawn listeners. Disable or stop the service properly.
  • Multiple Compose projects: The same port can be used by a different project. Use docker ps --filter "publish=PORT" to locate it.
  • Binding to 0.0.0.0 unnecessarily exposes services externally. Use 127.0.0.1 for local-only development.
  • Windows excluded ports: Even with no visible listener, a port in an excluded range won’t bind. Choose a different port.

Performance notes

  • On macOS/Windows (Docker Desktop), published ports are forwarded through a user-space networking layer. Publishing many ports can add overhead. Consolidate behind a single reverse proxy port when possible.
  • Binding to 127.0.0.1 avoids external firewall paths and can be slightly cheaper than 0.0.0.0 for local dev.
  • On Linux, iptables-based NAT for -p is efficient, but if you need maximum throughput and lowest latency, use --network host (security implications apply) or keep the number of published ports minimal.

Tiny FAQ

  • Q: Can Docker choose a random host port?

    • A: Yes. Use -p :CONTAINERPORT with docker run or "HOSTIP::CONTAINERPORT" in Compose. Docker will select a free host port.
  • Q: I freed the port, but I still get the error. Why?

    • A: Another process may have grabbed it in the meantime, a service restarted, or the port is in an excluded range on Windows. Re-run the checks and consider using a different host port.
  • Q: How do I see which container owns a port?

    • A: docker ps --filter "publish=PORT" or docker inspect <container> | grep -i "HostPort".
  • Q: Is binding to 0.0.0.0 required?

    • A: No. Use 127.0.0.1 if you only need local access. Bind to a specific interface/IP when exposing externally.
  • Q: Does EXPOSE in Dockerfile cause conflicts?

    • A: No. EXPOSE is metadata. Conflicts occur only when you publish ports with -p/--publish or Compose ports.

Series: Docker

DevOps