Recently while working with Docker on SUSE Linux Enterprise Server 12 SP1, I encountered a puzzling scenario where containers were accessible locally but unreachable from external networks. Let me walk through the complete diagnostic process and solution.
First, I launched a basic nginx container:
docker run -d -p 8081:80 nginx:alpine --name nginxtest
Local access worked perfectly:
curl http://localhost:8081
<!-- [...] -->
<title>Welcome to nginx!</title>
<!-- [...] -->
But external access failed when trying to reach http://server-ip:8081
from another machine.
The key network interfaces showed:
docker0 Link encap:Ethernet HWaddr 02:49:68:4D:40:9B
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
Bridge configuration appeared normal:
bridge name bridge id STP enabled interfaces
docker0 8000.0249143a607f no veth0e4b1f4
veth1f2fcc2
The NAT table revealed potential issues:
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
MASQUERADE tcp -- 172.17.0.2 172.17.0.2 tcp dpt:80
While the port mapping was configured in Docker:
0.0.0.0:8081->80/tcp
The key issue stemmed from the net.ipv4.ip_forward = 0
setting in /etc/sysctl.conf
combined with network service restarts. After running wicked
service restart, the IP forwarding got disabled.
First, enable IP forwarding permanently:
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Then verify the Docker network configuration:
docker network inspect bridge | grep -i masquerade
For immediate testing, you can add explicit iptables rules:
sudo iptables -A FORWARD -i eth0 -o docker0 -j ACCEPT
sudo iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
If the issue persists, consider these additional steps:
# Check for conflicting services
sudo netstat -tulnp | grep 8081
# Try host network mode for testing
docker run --network host -d nginx:alpine
For production environments, I recommend creating custom bridge networks:
docker network create --driver bridge my_custom_net
docker run -d --network my_custom_net -p 8081:80 nginx:alpine
After applying the fix, verify with:
cat /proc/sys/net/ipv4/ip_forward # Should return 1
sudo iptables -L -n -v | grep FORWARD
curl -I http://your-server-ip:8081
I recently encountered a perplexing scenario where my Docker containers responded to local requests but remained inaccessible from external networks. Here's what I observed:
# Local access works
curl http://localhost:8081
<title>Welcome to nginx!</title>
# External access fails (timeout)
http://10.etc.etc.etc:8081
The problem emerged after running systemctl restart wicked
, suggesting network configuration changes. Let's examine the current state:
# Bridge network status
ifconfig docker0
docker0 Link encap:Ethernet HWaddr 02:49:68:4D:40:9B
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
# Container port mapping
docker ps
0.0.0.0:8081->80/tcp
The iptables configuration reveals potential forwarding issues:
iptables -nt nat -L
Chain DOCKER (2 references)
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8081 to:172.17.0.2:80
Notice the MASQUERADE rules for other ports but potential missing elements for our case.
These commands help verify connectivity at different levels:
# Check port listening status
ss -tulnp | grep 8081
# Test local container access
docker exec -it nginxtest wget -qO- localhost:80
# Verify external interface accessibility
ip route get 10.etc.etc.etc
After thorough investigation, here's the step-by-step resolution:
# 1. Ensure proper IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# 2. Update iptables rules
iptables -I FORWARD 1 -i eth0 -o docker0 -j ACCEPT
iptables -I FORWARD 1 -i docker0 -o eth0 -j ACCEPT
# 3. Verify Docker network binding
docker network inspect bridge | grep host_binding_ipv4
# 4. Restart Docker service with clean networking
systemctl restart docker
# 5. For persistent changes, update sysctl.conf
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
If standard port mapping fails, consider these alternatives:
# Use host networking mode
docker run --network host nginx:alpine
# Or expose ports to specific interface
docker run -d -p 10.etc.etc.etc:8081:80 nginx:alpine
# For production environments, use Docker Swarm or Kubernetes:
docker service create --publish published=8081,target=80 nginx:alpine
- Always document network changes
- Use version-controlled Docker Compose files for port mappings
- Implement health checks for critical services
- Consider using
--publish-all
flag during development
# Example health check in Dockerfile
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:80/ || exit 1