How to Force Docker to Bind Ports to IPv4 Interfaces Only


2 views

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