Docker Error Guide: 'driver failed programming external connectivity' — Port Publish Fails
Fix 'driver failed programming external connectivity on endpoint': a port already in use, a stale iptables rule, or a dead daemon. Free the port or restart Docker to recover.
- #docker
- #troubleshooting
- #errors
- #networking
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
A container fails to start because Docker cannot wire up its published port:
Error response from daemon: driver failed programming external connectivity on endpoint web (a1b2...): Bind for 0.0.0.0:8080 failed: port is already allocated
When you publish a port (-p 8080:8080), Docker’s network driver programs host firewall/NAT rules to forward that host port to the container. If it cannot — because the host port is already taken, a stale rule from a crashed container remains, or the daemon’s iptables state is inconsistent — it aborts with driver failed programming external connectivity. The trailing detail (usually port is already allocated or a Bind error) tells you why.
Symptoms
docker run -pordocker compose upfails naming an endpoint and a host port.- The tail reads
port is already allocatedorBind for 0.0.0.0:<port> failed. - A container that crashed left a port “allocated” even though nothing is listening.
- The same compose stack starts fine after a Docker daemon restart.
- Two services (or two Compose projects) try to publish the same host port.
Common Root Causes
- Host port already in use by another container or a non-Docker process (a local nginx, a dev server, systemd-resolved on 53).
- Stale NAT/iptables rule from a container that crashed or was killed uncleanly, leaving the port “allocated” in Docker’s view.
- Two containers publishing the same host port, often the same Compose service scaled or two projects colliding.
- Docker’s iptables state got out of sync after a firewall reload (
firewalld/ufw) flushed Docker’s chains. - Rootless/port-permission issues when binding privileged ports (<1024) without the right configuration.
Diagnostic Workflow
First, see what already holds the host port. Check Docker’s own view and the OS’s:
docker ps
sudo ss -ltnp | grep ':8080'
If ss shows a non-Docker process, that program owns the port. If it shows nothing but Docker still reports “allocated”, the culprit is a stale rule. List containers that publish the port:
docker ps -a --format '{{.Names}}\t{{.Ports}}' | grep 8080
Remove a stale/dead container holding the mapping:
docker rm -f <container>
If Docker’s iptables state is inconsistent, restarting the daemon reprograms the rules cleanly:
sudo systemctl restart docker
Choose a non-conflicting host port in Compose rather than fighting over one:
services:
web:
image: registry.example.com/myapp:1.4.2
ports:
- "8081:8080" # host 8081 -> container 8080
Then retry:
docker compose up -d
docker ps
Example Root Cause Analysis
A team ran two independent Compose stacks on the same host: an internal dashboard and a new API. Both docker-compose.yml files happened to publish - "8080:8080". The dashboard started at boot; when CI later deployed the API with docker compose up -d, it failed with driver failed programming external connectivity on endpoint api ...: Bind for 0.0.0.0:8080 failed: port is already allocated.
sudo ss -ltnp | grep ':8080' showed the dashboard’s docker-proxy already bound to host port 8080, confirming a straightforward collision rather than a stale rule. Because both stacks legitimately needed to be reachable, the fix was to remap the API to a free host port: - "8081:8080" in its Compose file, fronted by the reverse proxy. After docker compose up -d, both stacks ran side by side.
Separately, the team hit the stale-rule variant once when a container was killed with kill -9 on the daemon: Docker still considered 8080 allocated though ss showed nothing listening. There, docker rm -f of the dead container followed by sudo systemctl restart docker cleared the orphaned NAT rule.
Prevention Best Practices
- Assign unique host ports across stacks and document them; a small port map prevents most collisions.
- Check the port before publishing:
sudo ss -ltnp | grep ':<port>'in deploy scripts to fail fast with a clear message. - Clean up dead containers with
docker rm -f(anddocker container prune) so stale mappings do not linger. - Restart Docker after firewall reloads.
firewalld/ufwreloads can flush Docker’s iptables chains;systemctl restart dockerreprograms them. - Front services with a reverse proxy so only one host port (80/443) is published and internal services stay on the Docker network. See the Docker stack guides.
Quick Command Reference
# What holds the host port? (Docker + OS view)
docker ps
sudo ss -ltnp | grep ':8080'
# Which container publishes it?
docker ps -a --format '{{.Names}}\t{{.Ports}}' | grep 8080
# Remove a stale/dead container
docker rm -f <container>
# Reprogram Docker's iptables/NAT rules
sudo systemctl restart docker
Conclusion
driver failed programming external connectivity means Docker could not bind a published host port — usually because it is already allocated, or a stale NAT rule from a dead container remains. Use sudo ss -ltnp to find the real owner, remap to a free port in Compose, remove orphaned containers, and restart the daemon if its firewall state drifted. Unique host ports plus a port-availability check in your deploy flow keep this error from recurring.
Get 500 Battle-Tested DevOps AI Prompts — Free
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.