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.
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:
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!