The 'listen tcp6 bind: address already in use' error occurs when Docker attempts to bind a container port to an IPv6 address that's already occupied. Find and stop the conflicting process, bind to IPv4 only, or use a different port.
The "listen tcp6 [::]:80: bind: address already in use" error in Docker occurs when you try to start a container with port mapping, but the specified port is already occupied on the IPv6 network stack. By default, Docker binds to both IPv4 (0.0.0.0) and IPv6 (::) addresses when you use port mapping like `-p 80:80`. The `[::]:` in the error message indicates Docker is trying to bind to all IPv6 interfaces on port 80. The double colon `::` is IPv6 shorthand for "all zeros" (equivalent to 0.0.0.0 in IPv4). This error typically means another process, Docker container, or system service is already listening on that port. Common culprits include web servers like nginx or Apache, other Docker containers, or services that started automatically on boot. The tcp6 socket type can accept both IPv4 and IPv6 connections, so even an IPv6 binding can block IPv4 connections to the same port.
Find which process is occupying the port using lsof or netstat. Since the error mentions tcp6, check both IPv4 and IPv6 bindings:
# Check both IPv4 and IPv6 bindings on the port
sudo lsof -i :80
# Or use netstat to see all listeners
sudo netstat -tlnp | grep :80
# On systems with ss (modern replacement for netstat)
sudo ss -tlnp | grep :80Look for processes in the output - common ones include:
- nginx - nginx web server
- apache2 or httpd - Apache web server
- docker-proxy - another Docker container
- node - Node.js application
If a web server or other service is using the port, stop it:
# Stop nginx
sudo systemctl stop nginx
sudo systemctl disable nginx # Prevent it from starting on boot
# Stop Apache
sudo systemctl stop apache2 # Debian/Ubuntu
sudo systemctl stop httpd # RHEL/CentOS
sudo systemctl disable apache2
# Stop any other conflicting service
sudo systemctl stop <service-name>If you need the service to coexist with Docker, consider changing its port configuration instead of disabling it.
Another Docker container might be using the port:
# List running containers and their ports
docker ps --format "table {{.Names}} {{.Ports}}"
# Find containers specifically using port 80
docker ps --filter "publish=80"
# Stop the conflicting container
docker stop <container_name>If using docker-compose, make sure you're not running multiple compose files that use the same port.
If you only need IPv4 connectivity, explicitly bind to 0.0.0.0 to skip IPv6:
# Bind only to IPv4
docker run -p 0.0.0.0:80:80 myimage
# In docker-compose.yml
services:
web:
ports:
- "0.0.0.0:80:80"This tells Docker to only create the IPv4 binding, which can avoid conflicts if another process is only using the IPv6 binding (or vice versa).
If you can't stop the conflicting process, map to a different host port:
# Use port 8080 on the host instead of 80
docker run -p 8080:80 myimage
# In docker-compose.yml
services:
web:
ports:
- "8080:80"Then access your application at http://localhost:8080 instead of http://localhost:80.
Sometimes stopped containers or stale network configurations hold ports:
# Remove all stopped containers
docker container prune
# Remove unused networks (can release port bindings)
docker network prune
# If using docker-compose, clean up properly
docker-compose down
# Nuclear option: stop all containers and clean up
docker stop $(docker ps -aq)
docker container prune -fThen restart the Docker daemon to ensure clean state:
sudo systemctl restart dockerIf a stale docker-proxy is holding the port, find and kill it:
# Find docker-proxy processes
ps aux | grep docker-proxy
# Find which one is using port 80
sudo lsof -i :80 | grep docker-proxy
# Kill the specific process (replace PID with actual number)
sudo kill <PID>
# If it won't die, force kill
sudo kill -9 <PID>After killing stale proxies, restart Docker to ensure clean state.
### Understanding IPv6 Binding in Docker
When you use -p 80:80, Docker creates bindings on both:
- 0.0.0.0:80 (IPv4, all interfaces)
- [::]:80 (IPv6, all interfaces)
The tcp6 socket with [::]: can actually accept both IPv4 and IPv6 connections due to IPv4-mapped IPv6 addresses. This is why a single tcp6 binding can block access even if you're only connecting via IPv4.
You can see this with docker ps:
PORTS
0.0.0.0:80->80/tcp, :::80->80/tcp### Binding to Specific Interfaces
To avoid conflicts, bind to specific IP addresses:
# Only localhost (IPv4)
docker run -p 127.0.0.1:80:80 myimage
# Only localhost (IPv6)
docker run -p [::1]:80:80 myimage
# Specific network interface
docker run -p 192.168.1.100:80:80 myimage### Disabling IPv6 in Docker
If you don't need IPv6 at all, you can disable it at the Docker daemon level:
// /etc/docker/daemon.json
{
"ipv6": false
}Then restart Docker: sudo systemctl restart docker
### Checking Port Availability Before Starting
Before running containers, verify port availability:
# Check if port 80 is available
! (sudo lsof -i :80 > /dev/null 2>&1) && echo "Port 80 is free" || echo "Port 80 is in use"
# Or use netcat
nc -z localhost 80 && echo "Port 80 in use" || echo "Port 80 is free"### systemd Socket Activation Conflicts
On modern Linux systems, systemd might activate sockets on-demand. Check for socket units:
# List active socket units
systemctl list-units --type=socket
# Check if a specific port is managed by systemd
sudo ss -tlnp | grep systemdIf systemd is managing the port, you may need to disable the socket unit rather than just the service.
image operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker
cannot open '/etc/passwd': Permission denied
How to fix 'cannot open: Permission denied' in Docker
Error response from daemon: failed to create the ipvlan port
How to fix 'failed to create the ipvlan port' in Docker
toomanyrequests: Rate exceeded for anonymous users
How to fix 'Rate exceeded for anonymous users' in Docker Hub