SSH tunneling facilitates secure communication between Docker containers and servers or clients. It may also serve as a means of secure remote access to resources needed by containers.
In this tutorial, we’ll describe how to access the host’s SSH tunnel from a Docker container.
2. Create an SSH Tunnel to the Host Network
To access the host’s SSH tunnel from a Docker container, we’ll port-forward a listening port in the Docker container to a socket address through the host. Of course, for this to work, the Docker container must be authenticated to gain access to the host via SSH.
We can ensure said authentication by manually copying the container’s public SSH key to the host’s authorized_keys file. We could also do this with ssh-copy-id or scp, but the host must have password authentication enabled for SSH.
2.1. Port-Forwarding From the Docker Container to Access the Host’s SSH Tunnel
Once the Docker container has access to the host via SSH, we can try accessing the host’s SSH tunnel from the Docker container. To do this, we’ll forward connections to a socket address through the host from a listening port in the container using ssh -L:
$ ssh -L [listening port]:[socket address] username@hostname
For instance, we can forward connections from port 7676 on the Docker container to localhost:80:
$ ssh -L 7676:localhost:80 baeldung@linux
The command above will forward connections from port 7676 on the container’s loopback interfaces to localhost:80 through the host, baeldung@linux.
For clarity, if we do not add a bind address before the listening port or use ‘*’ as the bind address, the port will only be available to the container’s loopback address.
But if we use 0.0.0.0 as the bind address, the listening port will be available to all interfaces:
$ ssh -L 0.0.0.0:7676:localhost:80 baeldung@linux
We can also forward connections from a specific socket address on the container’s network – say the first ethernet interface and the listening port:
$ ssh -L 172.17.0.2:7676:127.0.0.1:22 baeldung@linux
2.2. Running SSH in the Background
When we port-forward using the syntaxes in the previous section, we’ll log into the host terminal through the Docker container. But, since we only want access to the host’s SSH tunnel, we don’t need to log into the terminal. To avoid this, we’ll run ssh in the background.
To run ssh in the background, we can add the -f option to the command:
$ ssh -f -L 7676:localhost:80 baeldung@linux
However, that will throw an error saying “Cannot fork into background without a command to execute”. So, to avoid this error, we’ll add option –N to the command:
$ ssh -f -N -L 7676:localhost:80 baeldung@linux
After running this command, we can reach the host’s SSH tunnel without logging into its terminal. The -N option directs ssh to run without executing a remote command.
Killing the background SSH process disconnects the container’s access to the host’s SSH tunnel.
In some cases, we might get an error saying “bind [::1]:7676: Cannot assign requested address”. We get the error message because ssh is trying to bind our listening port to an IPv6 address. To remove this error, we’ll add the option -4 to the command, forcing ssh to use only the IPv4 address:
$ ssh -4 -f -N -L 7676:localhost:80 baeldung@linux
2.3. Confirming Access to the Host’s SSH Tunnel
To confirm that our Docker container is connected to the host’s SSH tunnel, we can try to connect to the listening port or local socket address from the container.
For instance, in our illustration, the host is an Nginx server, and we’re forwarding connections to the container’s listening port 7676 to localhost:80 through the host. So, when we curl to port 7676 in the container using a loopback address, we should get the same result as when we connect to localhost:80 from the host:
# curl localhost:7676 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...truncated... <h1>Welcome to nginx!</h1> ...truncated... </html>
Running the port-forwarding command ssh -L in verbose mode can also help us confirm the tunnel access.
In this article, we learned how to access the host’s SSH tunnel from a Docker container in the foreground and in the background. Then, we briefly covered ways to confirm a Docker container’s connection to its host’s SSH tunnel.