When running Docker containers with port forwarding, you might notice that Docker binds to IPv6 interfaces by default, even when IPv6 is disabled on your host system. This behavior can be particularly frustrating when:
- Your host has explicitly disabled IPv6 (as shown in the Digital Ocean example)
- Your application only needs IPv4 connectivity
- You're troubleshooting network connectivity issues
Docker's default networking behavior follows the Linux kernel's preference for IPv6 when available. Even when IPv6 is disabled at the system level, Docker might still attempt to bind to IPv6 addresses, resulting in output like:
# lsof -OnP | grep LISTEN
docker 9629 root 7u IPv6 ... TCP *:8000 (LISTEN)
There are several ways to force Docker to bind ports to IPv4 interfaces only:
Method 1: Using the --ip Flag
When starting the Docker daemon, you can explicitly specify IPv4 binding:
# Edit your Docker daemon configuration (usually /etc/docker/daemon.json)
{
"ip": "0.0.0.0",
"ip6": ""
}
# Then restart Docker
sudo systemctl restart docker
Method 2: Container-Specific Binding
For individual containers, specify the IPv4 address when running the container:
docker run -p 0.0.0.0:8000:8000 -i -t colinsurprenant/ubuntu-raring-amd64 /bin/bash
Method 3: System-Wide Kernel Parameters
To ensure all applications (including Docker) prefer IPv4:
# Add to /etc/sysctl.conf
net.ipv6.bindv6only = 0
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
# Apply changes
sysctl -p
After implementing any of these methods, verify the binding with:
ss -tulnp | grep 8000
# Should show IPv4 binding only
tcp LISTEN 0 128 0.0.0.0:8000 0.0.0.0:*
For production environments, consider these additional measures:
# Create a custom Docker network with IPv4 only
docker network create --ipv6=false my_ipv4_network
# Run container with explicit network binding
docker run --network my_ipv4_network -p 8000:8000 your_image
When running Docker containers with port forwarding (-p
flag), Docker by default binds to both IPv4 and IPv6 interfaces. This behavior persists even when IPv6 is disabled at the system level, as shown in your lsof
output where port 8000 appears as IPv6 only.
There are several effective methods to enforce IPv4 binding:
Method 1: Docker Daemon Configuration
Edit or create /etc/docker/daemon.json
:
{
"ipv6": false,
"ip": "0.0.0.0"
}
Then restart the Docker service:
sudo systemctl restart docker
Method 2: Explicit IP Binding in Run Command
Specify the IPv4 address when running containers:
docker run -p 0.0.0.0:8000:8000 your_image
Method 3: System-wide IPv6 Disable (Persistent)
Edit /etc/sysctl.conf
:
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
Apply changes:
sudo sysctl -p
After applying changes, verify with:
sudo lsof -i -P -n | grep LISTEN
sudo netstat -tulnp | grep docker
You should see your forwarded ports binding to IPv4 addresses.
For compose files, specify the IP explicitly:
version: '3'
services:
web:
ports:
- "0.0.0.0:8000:8000"
For stubborn cases, try these additional parameters:
echo 'net.ipv6.conf.all.disable_ipv6 = 1' >> /etc/sysctl.conf
echo 'net.ipv6.conf.default.disable_ipv6 = 1' >> /etc/sysctl.conf
echo 'net.ipv6.conf.docker0.disable_ipv6 = 1' >> /etc/sysctl.conf