Tunneling SSH Connections in Docker

A showcase how to develop locally with Docker, using a remote database over a secure SSH tunnel. No Docker hacking, no firewall tinkering.

.com software
2 min readJan 10, 2022
Two separate walls connect via a bunch of mixed wires. The wires looks like thunders.
Photo by israel palacio on Unsplash

Usually, we develop our apps using local database instances. It’s easy and dead simple. Just add a database to the docker-compose stack. Sometimes, however, it is required to connect to a remote database. We also want that connection to be secure. What if someone is listening or logging the Internet traffic along the way?

The easiest solution to this is an SSH tunnel. To allow Docker to access such a tunnel is not a trivial task. To let containers talk to an SSH tunnel we will make it part of our docker-compose stack.

Example database server with an SSH access

Let’s run a free-tier RDS instance in AWS. Since the instance is not going to be publicly available:

AWS database instance connectivity settings form. The “No” option is checked.

we also need a “bastion host” to connect. Let’s run additional, free-tier EC2 instance. After wiring the RDS and EC2 together, we now have all puzzles required to start.

Including the tunneling service in the docker-compose stack

There’s an excellent Docker image in the Docker hub called cagataygurturk/docker-ssh-tunnel. It does the heavy lifting of keeping the tunnel open. The image is based on Alpine Linux — it’s fast, slim and effective.

All we need to do is create the service in the docker-compose stack:

services:
// … skipped for brevity
mysql_tunnel:
image: cagataygurturk/docker-ssh-tunnel
volumes:
- $HOME/.ssh:/root/ssh:ro
environment:
TUNNEL_HOST: 'ec2-user@3.120.xx.xxx -i /root/.ssh/ec2.pem'
REMOTE_HOST: database-1.xxxxxx.eu-central-1.rds.amazonaws.com
LOCAL_PORT: 3306
REMOTE_PORT: 3306

The container expects the /root/ssh directory to be mounted with your SSH keys. The container during the start will copy the contents of this directory, push them to the /root/.ssh/directory and set proper permissions — otherwise the SSH agent will complain about the permissions.

Mine directory contains the ec2.pem certificate required to connect to the EC2 instance, that’s why I’m using it as a part of the TUNNEL_HOST variable. Details of the connection can be configured in the SSH’s config file as well.

The docker-compose services can now easily connect to this database using hostname mysql_tunnel and port 3306 as if the database was local. Simple and effective, good luck!

--

--

.com software

Father • PHP developer • entrepreneur • working for a €1bn unicorn startup as a backend engineer >>> https://bit.ly/dotcom-software