Using ubuntu tusty, there is a service running on a remote machine, that I can access via port forwarding through an ssh tunnel from localhost:9999
.
I have a docker container running. I need to access that remote service via the host's tunnel, from within the container.
I tried tunneling from the container to the host with -L 9000:host-ip:9999
, then accessing the service through 127.0.0.1:9000
from within the container fails to connect. To check wether the port mapping was on, I tried
nc -luv -p 9999 # at host
nc -luv -p 9000 # at container
following this, parag. 2 but there was no perceived communication, even when doing
nc -luv host-ip -p 9000
at the container
I also tried mapping the ports via docker run -p 9999:9000
, but this reports that the bind failed because the host port is already in use (from the host tunnel to the remote machine, presumably).
So my questions are
1 - How will I achieve the connection? Do I need to setup an ssh tunnel to the host, or can this be achieved with the docker port mapping alone?
2 - What's a quick way to test that the connection is up? Via bash, preferably.
Thanks.
On my side, running Docker in Windows Subsystem for Linux (WSL v1), I couldn't use docker0 connection approach.
host.docker.internal
also doesn't resolve (latest docker version).However, I found out I could directly use the host-ip insider my docker container.
ipconfig
), e.g.192.168.0.5
-
docker exec -it d6b4be5b20f7 /bin/bash
-
apt-get update && apt-get install iputils-ping
-
ping 192.168.0.5
Apparently, in Windows, you can directly connect from within containers to the host using the official host ip.
My 2 cents for Ubuntu 18.04 - a very simple answer, no need for extra tunnels, extra containers, extra docker options or exposing host.
Simply, when creating a reverse tunnel make sure ssh binds to all interfaces as, by default, it binds ports of the reverse tunnel to localhost only. For example, in putty make sure that option Connection->SSH->Tunnels
Remote ports do the same (SSH-2 only)
is ticked. This is more or less equivalent to specifying the binding address0.0.0.0
for the remote part of the tunnel (more details here):However, this did not work for me unless I allowed the
GatewayPorts
option in my sshd server configuration. Many thanks to Stefan Seidel for his great answer.In short: (1) you bind the reverse tunnel to 0.0.0.0, (2) you let the sshd server to accept such tunnels.
Once this is done I can access my remote server from my docker containers via the docker gateway
172.17.0.1
and port bound to the host.I'd like to share my solution to this. My case was as follows: I had a PostgreSQL SSH tunnel on my host and I needed one of my containers from the stack to connect to a database through it.
I spent hours trying to find a solution (Ubuntu + Docker 19.03) and I failed. Instead of doing voodoo magic with
iptables
, doing modifications to the settings of the Docker engine itself I came up with a solution and was shocked I didn't thought of this earlier. The most important things was I didn't want to use thehost
mode, security first.Instead of trying to allow a container to talk to the host, I simply added another service to the stack, which would create the tunnel, so other containers could talk to easily without any hacks.
After configuring a host inside my
~/.ssh/config
:And adding a service to the stack:
The PHP container started talking through the tunnel without any problems:
Just remember to put your public key inside that host if you haven't already:
I'm pretty sure this will work regardless of the OS used (MacOS / Linux).
Using your hosts network as network for your containers via
--net=host
or in docker-compose vianetwork_mode: host
is one option but this has the unwanted side effect that (a) you now expose the container ports in your host system and (b) that you cannot connect to those containers anymore that are not mapped to your host network.In your case, a quick and cleaner solution would be to make your ssh tunnel "available" to your docker containers (e.g. by binding ssh to the
docker0
bridge) instead of exposing your docker containers in your host environment (as suggested in the accepted answer).Setting up the tunnel:
For this to work, retrieve the ip your
docker0
bridge is using via:you will see something like this:
Now you need to tell ssh to bind to this ip to listen for traffic directed towards port 9000 via
Without setting the bind_address,
:9000
would only be available to your host's loopback interface and not per se to your docker containers.Side note: You could also bind your tunnel to
0.0.0.0
, which will make ssh listen to all interfaces.Setting up your application:
In your containerized application use the same
docker0
ip to connect to the server:172.17.0.1:9000
. Now traffic being routed through yourdocker0
bridge will also reach your ssh tunnel :)For example, if you have a "DOT.NET Core" application that needs to connect to a remote db located at
:9000
, your "ConnectionString" would contain"server=172.17.0.1,9000;
.on MacOS (tested in
v19.03.2
),1) create a tunnel on host
2) from container, you can use
host.docker.internal
ordocker.for.mac.localhost
ordocker.for.mac.host.internal
to reference host.example,
note from docker-for-mac official doc
I think you can do it by adding
--net=host
to your docker run. But see also this question: Forward host port to docker container