Connect to MongoDB from behind firewall via SSH Tunneling/Port Forwarding
Tags: mongodb, node, ssh, firewall
Published: 2018-04-07 14:45:29

---
title: Connect to MongoDB from behind firewall via SSH Tunneling/Port Forwarding
published: true
description: 
tags: mongodb, nodejs, ssh, firewall
---

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](https://www.linode.com) or [https://www.digitalocean.com](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](https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets) if you're using Mac/Linux or [this](https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-putty-on-digitalocean-droplets-windows-users) 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:


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

```

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:


```js
node_modules/
id_rsa.ppk

```
   

## 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](https://thepracticaldev.s3.amazonaws.com/i/y55vqeuhfqi6slnwpbkh.png)

####Authentication tab:

![Studio3T authentication tab](https://thepracticaldev.s3.amazonaws.com/i/35t7dazoxlvxlerjbl11.png)

####SSH Tunnel tab:

![Studio3T SSH tunnel tab](https://thepracticaldev.s3.amazonaws.com/i/n71flh1zt0tkiyohy6oo.png)

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:


```js
npm i --save tunnel-ssh fs
```

Then make the following changes to the code:

```js
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
}

```