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:
- We want to use a tool like Studio3T for MongoDB, but the MongoDB port is blocked.
- 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
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
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:
Authentication tab:
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
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
}
Top comments (1)
Amazing. I was trying to connect to a postgreSQL database using a ssh port forwarding mechanism.
Tried several days until found your solution.
Thanks!