3

As a workaround for some operational silliness in a work project, I am trying to:

  1. Run Service A listening on localhost:4001 and Service B listening localhost:4002.
  2. Run Nginx inside a Docker container; internally listening on 0.0.0.0:80
  3. Set up Docker listening on localhost:80 on the host system, forwarding requests to port 80 in the Nginx container.
  4. Set up Nginx to forward localhost:80/a to localhost:4001, and to forward localhost:80/b to localhost:4002.

I can write my own nginx.conf file, but for operational and organizational reasons I am stuck with running Nginx inside Docker.

But is it possible to have the Nginx server running inside a container proxy requests to the loopback device of the host system?

A diagram of what I am attempting to do:

                     ┌──────────────────┐
                     │                  │
                     │ My web browser   │─┐
                     └──────────────────┘ │
                                          │
         ┌────────────────────────────────┼───────┐
         │                                │       │
         │      ┌──────────────────────┐  │       │
         │      │                      │← │       │
     ┌───┼──────│ Nginx (0.0.0.0:80)   │──┘       │
     │ ┌─┼──────│                      │          │
     │ │ │      └──────────────────────┘          │
     │ │ │                                        │
     │ │ │ Docker (localhost:80 -> 172.17.0.1:80) │
     │ │ └────────────────────────────────────────┘
     │ └────────────────────────────┐
     │                              │
    ↓│                             ↓│
 ┌───────────────────────────┐  ┌───────────────────────────┐
 │                           │  │                           │
 │ Daemon A (localhost:4001) │  │ Daemon B (localhost:4002) │
 └───────────────────────────┘  └───────────────────────────┘
7
  • By definition, localhost is not accessible from the network, virtual or otherwise.
    – Daniel B
    Commented Aug 16, 2021 at 16:32
  • @DanielB as in, the loopback device of my machine is definitionally inaccessible from the virtual network inside Docker? Is there some workaround? Commented Aug 16, 2021 at 16:38
  • If the answer is "no, it's 100% impossible" then that's fine and I will accept it @DanielB. Commented Aug 16, 2021 at 19:38
  • Nothing is impossible. 😉 // Perhaps elaborate on the restrictions that are forcing you to not run nginx on the host so we get a clearer picture on what methods could be used to work around that.
    – Daniel B
    Commented Aug 17, 2021 at 8:05
  • @DanielB the restriction is that this is the "local dev" setup for a handful of developers, and we don't want to force them to install and set up Nginx locally. Personally I don't think it's a big deal to set up Nginx, but the expectation is that we run as much as possible inside Docker, and only occasionally should developers be running services outside of containers. In this example, the service simply isn't "Dockerized" yet. I intend this to be a short-term hack to keep the other devs from having to think about ops stuff. Commented Aug 20, 2021 at 13:10

1 Answer 1

2

By design, applications listening on localhost (127.0.0.1/8 or ::1/128) are accessible only locally on the same machine. Or, strictly speaking, from the same network namespace. By default, Docker containers have their own network namespace, which comes with another, separate instance of localhost.

So with default Docker networking what you want is not possible: a container cannot connect to the host’s localhost.

Docker also supports a special networking mode: host networking. If you specify this when launching a container, it will not be put in a separate network namespace but instead use the host network namespace. The host’s and container’s localhost will be the same. However, there are implications:

  • Port mappings will not be effective
  • You need to take care not to use a port twice
  • Host networking cannot be mixed with links

Depending on your setup, nginx losing access to other containers could not be acceptable.

You could instead use something like socat to make the port accessible to Docker containers:

docker run -d --restart=always --network=host alpine/socat TCP4-LISTEN:4001,fork,reuseaddr,interface=docker0 TCP4-CONNECT:localhost:4001

From your nginx container, you could then reach the host at 172.17.0.1 with default networking.

You can also try adding --add-host=host.docker.internal:host-gateway to the nginx container invocation to get a DNS name (host.docker.internal) that would then always work no matter the configuration. This only works in very recent versions of Docker.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .