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.

1 Like

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.