3

I tried:

services:
  susebox:
    build: .
    entrypoint: 
      - python3 
      - -m 
      - http.server
    ports:
      - 8000:8000
    extra_hosts:
      - "host.docker.internal:host-gateway"

but I can't do curl to host.docker.internal. ping is working on host.docker.internal but I still can't access the service running on localhost:

#inside of the container 

curl http://host.docker.internal:8080/
curl: (7) Failed to connect to host.docker.internal port 8080 after 0 ms: Connection refused

Also tried

network_mode: "host"

curl http://localhost:8080/ #this runs ok outside of container
curl: (7) Failed to connect to localhost port 8080 after 0 ms: Connection refused

but I still can't reach localhost from inside of docker container. I'm using rootless docker containers

너를 속였다
  • 899
  • 11
  • 26
  • 1
    You have exposed port 8000 to your local machine, not port 8080 which is what your curl is doing. – alex067 Jun 04 '22 at 14:59
  • @alex067 that curl cmd if from inside of container. there is http server running on 8080 on my localhost which I want to access from inside of container – 너를 속였다 Jun 04 '22 at 16:11
  • Then from inside the container you should connect to `host.docker.internal:8080` which is how your docker host (i.e. your development machine) is known. From inside the container, `localhost` is the container itself. – Zeitounator Jun 04 '22 at 16:31
  • @Zeitounator it does not work. see edit – 너를 속였다 Jun 04 '22 at 17:54
  • Are you running on linux, windows, or mac? Windows and mac run docker in a lightweight VM which effects how this can be done. `host.docker.internal` for instance, is only available on windows and mac docker. – NikNye Jun 04 '22 at 18:10
  • @NikNye I'm on Linux (Arch btw) – 너를 속였다 Jun 04 '22 at 18:14
  • I would suggest you edit the question and provide a lot more detail – alex067 Jun 04 '22 at 19:52
  • `Connection refused` <= I suspect your service on your machine only accepts connections from localhost (i.e. the same machine where it runs). – Zeitounator Jun 05 '22 at 03:48
  • @alex067 what more details do I need to add ? most people commenting/answing here dont even seem to know what rootless containers are or what OS i'm using even if linux is clearly tagged. – 너를 속였다 Jun 05 '22 at 06:05
  • @Zeitounator its darkhttpd server and I can even access it from my android phone – 너를 속였다 Jun 05 '22 at 06:07

1 Answers1

1

I'm assuming you're using the slirp4netns network driver, since that's what the documentation implicitly suggests.

Docker rootless runs slirp4netns with the --disable-host-loopback option, which prohibits connecting to 127.0.0.1:* on the host namespace, presumably for security reasons.

If the host service is listening on 0.0.0.0 you can try connecting to the local network IP of the host, for instance 192.168.1.100.

If you have to access a service listening on the host's 127.0.0.1 or don't want to change your configuration (e.g. because it's shared with others that don't use docker rootless), you could use socat to forward traffic between namespaces using a socket.

Suppose you want to access 127.0.0.1:8080 running on the host from inside a container. You would need 2 socat instances for that:

  1. An instance listening on a unix socket that forwards traffic to 127.0.0.1:8080:

    socat UNIX-LISTEN:/tmp/forward-docker.socket,fork TCP:127.0.0.1:8080
    
  2. An instance running on the docker namespace that forwards traffic to the socket created by the previous command:

    nsenter -U --preserve-credentials -n -t $(cat "$XDG_RUNTIME_DIR/docker.pid") -- socat TCP4-LISTEN:8080,reuseaddr,fork /tmp/forward-docker.socket
    

The trick here is that the networks are isolated between namespaces, but the filesystem is shared, so we use an unix socket to bridge the gap. Note that these commands run on the host. After that you can access that host port from inside any container.

If the service you're trying to access is running in another container and forwarding a port on the host, you can skip the first instance and only run the one in the namespace, but you would need to change the port, as it would have already been used by docker in the namespace, and forward to 127.0.0.1. For instance, let's say you are running a service like this:

docker network create another-net
docker run --rm -p 8080:8080 --net another-net python python -m http.server 8080

You only need command #2 but with a different port, for example 8081:

nsenter -U --preserve-credentials -n -t $(cat "$XDG_RUNTIME_DIR/docker.pid") -- socat TCP4-LISTEN:8081,reuseaddr,fork TCP:127.0.0.1:8080

And then from any other container you would access the new port.

An example bash script to do all that in a single easy command, with the option of binding different ports:

#!/bin/bash
set -e

PORTS=($(echo "$1" | grep -oP '^\d+(:\d+)?$' | sed -e 's/:/ /g'))
if [ -z $PORTS ]; then
    cat <<EOF
Usage:
$(basename "$0") SRC[:DEST]
    SRC: will be the port accessible inside the container
    DEST:
        the connection will be redirected to this port on the host.
        if not specified, the same port as SRC will be used
EOF
    exit 1
fi

SOURCE=${PORTS[0]}
DEST=${PORTS[1]-${PORTS[0]}}

SOCKFILE="$XDG_RUNTIME_DIR/forward-docker2host-${SOURCE}_$DEST.sock"
socat UNIX-LISTEN:"$SOCKFILE",fork TCP:127.0.0.1:$DEST &
nsenter -U --preserve-credentials -n -t $(cat "$XDG_RUNTIME_DIR/docker.pid") -- socat TCP4-LISTEN:$SOURCE,reuseaddr,fork "$SOCKFILE" &
echo forwarding $SOURCE:$DEST... use ctrl+c to quit
sleep 365d
David Rios
  • 351
  • 3
  • 5