I just set up a basic Nginx container with the same effects as my Docker Compose project where I stumbled in this problem.
# docker --version
Docker version 28.0.1, build 068a01e
# uname -promi
6.8.0-54-generic x86_64 x86_64 x86_64 GNU/Linux
# iptables --version
iptables v1.8.10 (legacy)
# lsb_release -d
No LSB modules are available.
Description: Ubuntu 24.04.2 LTS
Docker packages are from the docker repository:
https://download.docker.com/linux/ubuntu noble/stable amd64 Packages
Installed from there is:
# aptitude search "?origin (docker) ?installed"
i containerd.io - An open and reliable container runtime
i docker-buildx-plugin - Docker Buildx cli plugin.
i docker-ce - Docker: the open-source application container engine
i docker-ce-cli - Docker CLI: the open-source application container engine
i A docker-ce-rootless-extras - Rootless support for Docker.
i docker-compose-plugin - Docker Compose (V2) plugin for the Docker CLI.
/etc/docker/daemon.json
:
{
"data-root": "/docker-data/",
"storage-driver": "zfs",
"userland-proxy": true,
"default-address-pools": [
{
"base": "10.42.0.0/16",
"size": 24
},
{
"base": "2001:db8:affe:1::/64",
"size": 64
},
{
"base": "2001:db8:affe:2::/64",
"size": 64
},
{
"base": "2001:db8:affe:3::/64",
"size": 64
},
{
"base": "2001:db8:affe:4::/64",
"size": 64
}
],
"log-driver": "journald",
"log-opts": {
"tag": "{{.Name}}"
},
"ipv6": true,
"fixed-cidr-v6": "2001:db8::/64"
}
iptables before container run:
# iptables-save | grep -E '(^\*|DOCKER)'
*raw
*mangle
*nat
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A DOCKER -i docker0 -j RETURN
*filter
:DOCKER - [0:0]
:DOCKER-BRIDGE - [0:0]
:DOCKER-CT - [0:0]
:DOCKER-FORWARD - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-FORWARD
-A DOCKER ! -i docker0 -o docker0 -j DROP
-A DOCKER-BRIDGE -o docker0 -j DOCKER
-A DOCKER-CT -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A DOCKER-FORWARD -j DOCKER-CT
-A DOCKER-FORWARD -j DOCKER-ISOLATION-STAGE-1
-A DOCKER-FORWARD -j DOCKER-BRIDGE
-A DOCKER-FORWARD -i docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-USER -j RETURN
Running the container:
# docker run --name nginx-test --detach --publish <external ip>:80:80 nginx:alpine
a252ed336b8fcb397c82359d335d40283adb5a7b1de20d19a3cae57578d734b1
Container network:
# docker inspect nginx-test | jq '.[] | {(.Name) : .NetworkSettings.Networks}'
{
"/nginx-test": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "3e:be:bd:ca:ca:7f",
"DriverOpts": null,
"GwPriority": 0,
"NetworkID": "8f59354ae0fd77b8329b5076f670236b4b1d42d8db76bb81fdb09f7c5c8275db",
"EndpointID": "31b36b2c96f9ba677dade8a5c229bda7f966e5b1bbb1bf48d10f272e4027aa09",
"Gateway": "10.42.0.1",
"IPAddress": "10.42.0.2",
"IPPrefixLen": 24,
"IPv6Gateway": "2001:db8::1",
"GlobalIPv6Address": "2001:db8::2",
"GlobalIPv6PrefixLen": 64,
"DNSNames": null
}
}
}
iptables after container run:
# iptables-save | grep -E '(^\*|DOCKER)'
*raw
*mangle
*nat
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A DOCKER -i docker0 -j RETURN
-A DOCKER -d <external ip>/32 ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.42.0.2:80
*filter
:DOCKER - [0:0]
:DOCKER-BRIDGE - [0:0]
:DOCKER-CT - [0:0]
:DOCKER-FORWARD - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-FORWARD
-A DOCKER -d 10.42.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER ! -i docker0 -o docker0 -j DROP
-A DOCKER-BRIDGE -o docker0 -j DOCKER
-A DOCKER-CT -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A DOCKER-FORWARD -j DOCKER-CT
-A DOCKER-FORWARD -j DOCKER-ISOLATION-STAGE-1
-A DOCKER-FORWARD -j DOCKER-BRIDGE
-A DOCKER-FORWARD -i docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-USER -j RETURN
The docker-proxy is listening for the container:
# lsof +c 15 -Pni @<external ip>:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
docker-proxy 194855 root 7u IPv4 120503196 0t0 TCP <external ip>:80 (LISTEN)
Trying to reach the nginx from docker host:
# lynx -dump http://<external ip>/
Looking up <external ip>
Making HTTP connection to <external ip>
Alert!: Unable to connect to remote host.
lynx: Can't access startfile http://<external ip>/
# telnet <external ip> 80
Trying <external ip>...
telnet: Unable to connect to remote host: No route to host
# ping -c 2 <external ip>
PING <external ip> (<external ip>) 56(84) bytes of data.
64 bytes from <external ip>: icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from <external ip>: icmp_seq=2 ttl=64 time=0.082 ms
--- <external ip> ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1058ms
rtt min/avg/max/mdev = 0.062/0.072/0.082/0.010 ms
Ping internal IP:
# ping -c 2 10.42.0.2
PING 10.42.0.2 (10.42.0.2) 56(84) bytes of data.
From 147.78.88.200 icmp_seq=1 Time to live exceeded
From 147.78.88.200 icmp_seq=2 Time to live exceeded
--- 10.42.0.2 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1000ms
OK try it in the container namespace.
Map the docker network namespace to the normal network namespaces:
# ln -s /run/docker/netns /run/netns
# ip netns list
8e1cded88bd3 (id: 0)
# netns=8e1cded88bd3
# ip netns exec ${netns} ping -c 2 10.42.0.2
PING 10.42.0.2 (10.42.0.2) 56(84) bytes of data.
64 bytes from 10.42.0.2: icmp_seq=1 ttl=64 time=0.039 ms
64 bytes from 10.42.0.2: icmp_seq=2 ttl=64 time=0.027 ms
--- 10.42.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1019ms
rtt min/avg/max/mdev = 0.027/0.033/0.039/0.006 ms
# ip netns exec ${netns} lynx -dump http://10.42.0.2/ | head -1
Welcome to nginx!
So everything is up an running in the container.
Why can’t I reach it via external IP from docker host or even from outside?
Greetings,
Lars