Connect to MongoDB from behind firewall via SSH Tunneling/Port Forwarding

codeprototype

Kevin Le

Posted on April 7, 2018

Connect to MongoDB from behind firewall via SSH Tunneling/Port Forwarding

When a NodeJS application is deployed to Azure, Heroku or some other cloud services, there should be no trouble for the application to successfully connect to a MongoDB instance that is also on a cloud. But if we are behind a corporate firewall, the following following problems could arise:

  1. We want to use a tool like Studio3T for MongoDB, but the MongoDB port is blocked.
  2. For whatever reason, we don't want install a MongoDB instance on localhost for development. Instead we want to connect to a test MongoDB instance that is also on the cloud.

There are corporates who will not punch port 27017 opened in the firewall just for us developers. We can solve this firewall problem by using SSH Tunneling, also known as SHH Port forwarding.

First, signup for the most basic (read cheapest) cloud VPS such https://www.linode.com or https://www.digitalocean.com

There are 2 ways to authenticate to a VPS instance (DigitalOcean calls VPS instance a droplet; I refer to it later in the article as SSH server): (i) Username/password which is typical (ii) Public private RSA key pair

We focus on the latter "public private RSA key pair" in this article.

Follow this guide if you're using Mac/Linux or this if you're using Windows.

If you do your development work on multiple computers (for example Windows10 at work, Mac at home) or if you work on a project with other developers, for each public/private RSA key pair generated, upload the public key to the VPS instance.

To have the same code base between multiple computers and multiple developers, we want the NodeJS code to refer the private key file from the same directory. I'm assuming we choose the root directory of the NodeJS. On Windows, the private key is given the .ppk extension. Let's just copy to the root directory of the NodeJS project and call it id_rsa.ppk. For example:



$ cd [root NodeJS directory]
$ cp ~/.ssh/id_rsa id_rsa.ppk



Enter fullscreen mode Exit fullscreen mode

Do not forget to include this file in .gitignore so they won't be committed to git. For example, the content of .gitignore might be like:



node_modules/
id_rsa.ppk



Enter fullscreen mode Exit fullscreen mode

Connect Studio3T

Studio3T is a good tool to use with either your test or production MongoDB. After launching Studio3T, create a new connection with similar settings as below:

Server tab:

Studio3T server tab

Authentication tab:

Studio3T authentication tab

SSH Tunnel tab:

Studio3T SSH tunnel tab

If you didn't have a passphrase when you created the public private key pair, then check the box "My private key is not protected by a passphrase".

NodeJS programmatically

During development, we have to run a NodeJS application on a local machine which is behind the corporate firewall. Since the MongoDB that runs on the cloud usually listens to a port that is blocked the firewall, we have to change the code using the SSH Tunnel/Port forward technique like we did above.

First, bring in the necessary npm packages:



npm i --save tunnel-ssh fs


Enter fullscreen mode Exit fullscreen mode

Then make the following changes to the code:



const mongoose = require('mongoose');
const tunnel = require('tunnel-ssh');
const dev = process.env.NODE_ENV !== 'production';

if (dev) {
  const sshTunnelConfig = {
    agent: process.env.SSH_AUTH_SOCK,
    username: 'kevin',
    privateKey: require('fs').readFileSync('./id_rsa.ppk'),
    host: 'xx.yyy.zz.xyz', //IP adress of VPS which is the SSH server
    port: 22,
    dstHost: 'your-test-instance.mlab.com',
    dstPort: 31568, //or 27017 or something like that
    localHost: '127.0.0.1',
    localPort: 50001 //or anything else unused you want
  };

  tunnel(sshTunnelConfig, (error, server) => {
    if(error) {
        console.log("SSH connection error: ", error);
    }

  mongoose.connect(`mongodb://${Constants.DEV_DB_USERNAME}:${Constants.DEV_DB_PASSWORD}@127.0.0.1:50001/${some_db_name}`);
 //important from above line is the part 127.0.0.1:50001 
  });
} else {
  mongoose.connect('your-production-instance-uri'); //normal from before
}



Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
codeprototype
Kevin Le

Posted on April 7, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related