Can't connect via global DN to an apparently bound TCP port

Issue Summary

HTTP service/container will not accept TCP connections from the Internet.

Host Configuration

  • Windows Server 2022 v21H2 (build 20348.2113)
  • Ubuntu 22.04.3 LTS distro under WSL 2
  • Docker Compose v2.21.0
  • Docker Engine v24.0.7 (build afdd53b)

Background

I’m looking to deploy an HTTP-based service to the Internet on a Windows Server 2022 host (though this issue also manifests on my Win10 Pro hosts).

I’ve got the following docker-compose.yaml:

networks:
  solo_net:
    ipam:
      driver: default
      config:
        - subnet: 172.73.37.192/2
          ip_range: 172.73.37.192/2
          gateway: 172.28.37.254
services:
  ## Plain HTTP host service
  nginx:
    image: nginx:1-alpine
    container_name: nginx
    hostname: nginx
    networks:
      solo_net:
        ipv4_address: 172.73.37.192
    ports:
      - host_ip: 0.0.0.0
        mode: host
        target: 80
        published: 80
        protocol: tcp
  ## A test client on the same subnet a nginx
  sibling:
    build:
      dockerfile_inline: |
        FROM ubuntu:jammy
        RUN apt-get update && apt-get -y upgrade && apt-get -y install iputils-ping curl
    container_name: sibling
    hostname: sibling
    networks:
      solo_net:

I’ve confirmed that the “nginx” service/container is indeed running and listening to connections with the following:

## Confirm nginx is running and assigned IP is correct.
docker compose exec nginx ifconfig -a
## Confirm the sibling client on the same subnet can connect.
docker compose run --rm sibling /bin/bash -c "curl -v http://nginx/"
## Confirm the port 
Invoke-WebRequest -Uri http://localhost/

But when I try to curl, Invoke-WebRequest, or visit via browser my global Internet address, all I get are timeouts.

I’ve confirmed my firewalls—both on the host machine and on my LAN’s gateway—are correctly forwarding port 80 by standing up a Rebex Tiny Web Server. It responds to Internet-sourced HTTP requests as expected.

In fact, as a symptom of the problem: with the nginx service/container running, I can start the Rebex server and it binds to port 80 as a listener without issue. If Docker Engine was correctly binding a container to port 80, any other program trying to bind to that port should subsequently fail.

Attempted Workarounds

  • Building the image & running the HTTP service/container both with and without Docker Desktop (preferred config is to run Docker Engine installed directly into a Ubuntu LTS distro under WSL),
  • Changing both the target and destination port numbers.
  • Using short syntax on ports (thus, tried with both “ingress” and “host” port modes).
  • Not specifying static service/container IP addresses.
  • Not specifying IP Address Management (IPAM) for the Docker network.
  • Attaching the services to the default network (not specifying a network in the service elements).
  • Visiting the site via global IP address and assigned domain name.
  • Using other HTTP-capable images.
  • Confirming Docker Engine and Docker Compose versions to be the most recent stable.

Requested Support

Recommend a Docker (or Docker Compose) setting I seem to be overlooking.

By default, if a process binds a port inside a WSL2 distribution, it will be automatically bound to the hosts localhost interface, but to no other. You just happen to experience this with a docker container.

If I google the terms “windows portforwarding WSL2”, the first result is this blog post:

Note: Docker Desktop (which does not support Windows Server) uses WSL2 to operate its Docker Engine backend as well, but it does not suffer from this limitation.

Looking into this. Thank you for your prompt insight, @meyay.

EDIT: That was indeed the correct diagnosis of and solution to my problem. Thank you again, @meyay.