Accessing securely production services with SSH port forwarding

We’ve already talked about how to deploy your public SSH keys into your server using Ansible and GitHub. This time, I just want to share a simple approach to have access to your production services (MySQL, Elastic, RabbitMQ, etc.) without exposing publicly your services. You have different alternatives, probably the most common are using a VPN or use SSH port forwarding. Let’s see an example of the last one.

Consider that you have you cool side project running in Production. You are using some services such as MySQL, RabbitMQ and ElasticSearch. For debugging and having real data, you want to run some queries against MySQL, perform some queries to Elastic or spy some messages in RabbitMQ.

For accessing this production services from your development machine there are different options.

A. Open the ports publicly

This is not recommended because of the security risks. Anyone can just access your ElasticSearch and do whatever they want.

B. Run the services in different ports and make them publicly

Stop, please stop. I’m serious.

C. Set up a VPN and use it to connect

Now we’re talking. However, setting a VPN is a bit too much for me. If you’re interested, take a look to “How To Set Up an OpenVPN Server on Ubuntu 16.04”. The tutorial has lots of steps.

D. Use SSH port forwarding

The basic idea is to forward some of your local ports to a remote IP and ports using SSH. Imagine that you want to access your remote ElasticSearch that runs on port 9200. Let’s take a closer look to this option.

Let’s run the some commands!

If you make a curl to an error page should be shown.



And you should see the same if you are not running ElasticSearch in you local machine:

curl http://localhost:9200


Now, open a new tab and try:

ssh -L 9200:localhost:9200

First of all, it looks like a ssh command. Cool. If you don’t have your SSH public key deployed in your server, the command will ask for the root password, as you are used to. After entering the password, you will have access to your remote server. What’s the difference? What about if we try the curl command again?

curl http://localhost:9200


Bam! Our ElasticSearch on Production. What about if we want to include other services such as MySQL or RabbitMQ?

ssh -L 9200:localhost:9200 -L 3306:localhost:3306 -L 15672:localhost:15672

The -L options maps local ports with remote ports. In the example, we are mapping our localhost:9200 to (ElasticSearch). The same happens with MySQL (3306) and RabbitMQ Admin Plugin (15672).

What about if you don’t need to get access to the server, just do the forwarding?

ssh -nNT -L 9200:localhost:9200 -L 3306:localhost:3306 -L 15672:localhost:15672

The -nNT flags makes the command to wait until Control+C. If you don’t use it, the command still works but you will get prompt in the remote server.

What about if you’re running already ElasticSearch on your local machine and you want to map to another port? No problem.

ssh -nNT -L 9990:localhost:9200 -L 9991:localhost:3306 -L 9992:localhost:15672


Hope it helps!

If you want to know more about what you can do with SSH, take a look to this video “The Black Magic of SSH / SSH Can Do That?” by Bo Jeanes ;)