Docker container not reachable from outside

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

Which OS, how did you install Docker?

Hey bluepuma77,
sorry, added the information to my first post.
Greetings,
Lars

I just tried docker from the Ubuntu repositories. Same effekt.