Search code examples
dockerdocker-composedocker-network

docker-compose: open port in container but not bind it from host


(Note: the whole problem is because I misread the IP address of the docker network. The my-network is 172.22.0.0/16 instead of 127.22.0.0/16. I slightly modified the OP to reflect the original problem I encountered)

I created a service (a small web server) using docker-compose. The network part is defined as

services:
  service:
    image: ... (this image uses port 9000)
    ports:
      - 9000:9000
networks:
  default:
    name: my-network

After docker-compose up, I observe:

  • the host gets an IP address 172.22.0.1 and the client gets 172.22.0.2.
  • I can successfully ping the client from the host ping 127.22.0.2.
  • From the host machine: the web server can be reached using
    • 127.22.0.1:9000
    • 127.22.0.2:9000
    • localhost:9000
    • 192.168.0.10:9000 (This is the host's IP address in the LAN)

Now I want to restrict the access from the host using 172.22.0.2:9000 only. I feel this should be possible if I don't bind the container's 9000 port to the host's 9000 port. Then I deleted the ports: 9000:9000 part from the docker-compose.yml. Now I observe:

  • All the above four methods do not work now, including 127.22.0.2:9000
  • The client can still be pinged from the host using 127.22.0.2

I think: since the the host and the container are both in a bridge network my-network and have obtained their IP addresses. The web server should still be reachable from 127.22.0.2:9000. But this is not the case.

My questions:

  • why does it work like this? Shouldn't the host/container in the same subnet 127.22.0.0/16 be able to talk to each other freely?
  • How to achieve what I want: do not forward port 9000 from host to container and only allow accessing the container using its subnet IP address.

Solution

  • Your understanding of the networking is correct. Removing the port binding from the docker-compose.yml will remove the exposed port from the host. Since the host is also part of the virtual network my-network with an IP in the same subnet as the container, your service should be reachable from the host using the container IP directly.

    But I think, this is actually a simple typo and instead of

    127.22.0.0/16
    

    you actually have

    172.22.0.0/16
    

    as the subnet for my-network! This is a typical subnet used by docker in the default configuration, while 127.0.0.0/8 is always bound to the loopback device!

    So connecting to 127.22.0.2 will actually connect you to localhost - which is consistent with the symptoms you encountered:

    • connecting to 127.22.0.2:9000 will work only if the port is exposed on the host
    • you can always pint 127.22.0.2 since it is the loopback address