How to replicate Robo3T SSH configuration in nodejs and connect to MongoDB - node.js

I can connect to MongoDB with Robo-3T with SSH tunnel. But I fail to replicate the connection with Node.
This is the Robo-3T configuration
And this is my code. It seems that the SSH connection is ok, but the MongoClient.connect fails.
var config = {
username:'biomec',
Password:'xxxxxx',
host:'10.0.0.244',
port:22,
dstPort:27017,
localHost:'localhost',
localPort: 27017
};
var tunnel = require('tunnel-ssh');
var MongoClient = require('mongodb').MongoClient;
var server = tunnel(config, function (error, server) {
if(error){
console.log("SSH connection error: " + error);
}
console.log('SSH ok');
MongoClient.connect("mongodb://localhost:27017", function(err, db) {
if(err) {
console.log("Mongodb connection error: " + error);
}
console.log("We are connected to MONGO");
});
});

Related

Error: Timed out while waiting for handshake - Facing this issue while accessing mongodb from nodejs app deployed on Digitlal Ocean

I have a droplet of mongodb which I have created using SSH key. Then, I have created an app of NodeJs on digital ocean. (Configured it using github repo). In that app, I am using that mongodb droplet database. I am facing this handshake issue while accessing the database in my nodeJs App. I have tried both the ways:
a) To place the sshkey in the github repo
let mongoConfigArray = {
username: 'root',
connectTimeout: 99999,
host: dropletIpAddress,
privateKey: require('fs').readFileSync('./config/mysshkey'),
secure : true,
port: 22,
dstPort: 27017,
};
let connectionString = 'mongodb://user:pwd#localhost:27017/dbname';
var server = tunnel(mongoConfigArray, function (error, server) {
if(error){
console.log("SSH connection error: " + error);
}
mongoose.connect(connectionString, { useCreateIndex: true, useNewUrlParser: true, useUnifiedTopology: true });
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', function() {
// we're connected!
console.log("DB connection successful");
});
});
b) Or to place it somewhere online and accessing it when app runs.
request.get(fileUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// console.log(body);
mongoConfigArray.privateKey = body;
tunnel(mongoConfigArray, function (error, server) {
if(error){
console.log("SSH connection error: " + error);
}
mongoose.connect(connectionString, { useCreateIndex: true, useNewUrlParser: true, useUnifiedTopology: true });
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', function() {
// we're connected!
console.log("DB connection successful");
});
});
}
});
But I coudn't able to succeed it on the digital ocean app, while both of the ways working perfectly fine on local. Will be very thankfull if anyone knew how to resolve this issue.
Thanks

Issue with tunnel-ssh npm for ssh connection to mongo through mongoose

I am trying to establish a connection to remote mongo server through ssh tunnel using mongoose
The implementation code is:
import tunnel from 'tunnel-ssh';
const config = {
username: 'username',
Password: 'password',
host: process.env.SSH_SERVER, //192.168.9.104
port: 22,
dstHost: process.env.DESTINATION_SERVER, //192.168.9.104
dstPort: process.env.DESTINATION_PORT, //27017
localHost: '127.0.0.1',
localPort: 27017
};
this is the config that i have created while the connection is as follows:
class DB {
initDB() {
tunnel(config, (error, server) => {
if (error) {
console.log('SSH connection error: ' + error);
}
const url = 'mongodb://' + process.env.MONGO_URL; //localhost:27017/DBname
mongoose.connect(url, { useNewUrlParser: true });
mongoose.plugin(toJson);
mongoose.plugin(setProperties);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', function() {
console.log('DB connection successful');
});
});
}
}
When the function initDB() is invoked the following error pops up
SSH connection error: ConfigError: host not set
events.js:183
throw er; // Unhandled 'error' event
^
ConfigError: host not set
The host is already set but this error seems to be somewhere in the config part but I doesnt seem to single out to the exact reason
your "host" property at "config" var isn't defined. try using hard coded value instead of env var, if it works it means process can't read env vars which might be caused since you R not importing dotenv module

Connecting to mongodb through ssh username/password through nodejs

I am trying to connect to Mongodb through ssh username/password through nodejs as below :
var mongoose = require('mongoose');
var tunnel = require('tunnel-ssh');
var config = {
username : 'xyz',
host: 'xx-xxx-xx.com',
port:22,
password:'xxx',
dstPort:27017,
localPort:27017
};
console.log(tunnel);
var server = tunnel(config, function (error, server) {
if(error){
console.log("SSH connection error: " + error);
}
console.log(server);
mongoose.connect('mongodb://localhost:27017/myDB');
var db = mongoose.connection;
console.log(db);
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', function() {
console.log("DB connection successful");
});
});
But I am getting error as below :
DB connection error: { MongoError: connection 0 to localhost:27017 timed out
What is the issue here?
Probably is because you are missing the 'dstHost'in the config options.
The 'dstHost' must be the destination server url.
from official tunnel-ssh doc
var config = {
username:'root',
Password:'secret',
host:sshServer,
port:22,
dstHost:destinationServer,
dstPort:27017,
localHost:'127.0.0.1',
localPort: 27000
};
var tunnel = require('tunnel-ssh');
tunnel(config, function (error, server) {
//....
});

Connection to MongoDB with SSH in my Node App

My DB is with DigitalOcean and I'm trying to connect to it in my node app.
I've found a npm called tunnel-ssh however am having trouble connecting to it. My code is below.
It says DB connection successful, however when i do a console.log(mongoose) it shows the host and host as null.
If I do console.log(mongoose), after the console.log("DB connection successful"); then it shows me the host.
var tunnel = require('tunnel-ssh');
var config = {
agent : 'myuser',
host: 'xxx:xxx:xxx:xxx'
agent : process.env.SSH_AUTH_SOCK,
privateKey:require('fs').readFileSync('id_rsa'),
port:22,
dstPort:27010,
keepAlive: true
};
var server = tunnel(config, function (error, server) {
if(error){
console.log("SSH connection error: " + error);
}
mongoose.connect('mongodb://127.0.0.1:27017/mysuperdb');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', function() {
console.log("DB connection successful");
});
});
Here's the working code:
var tunnel = require('tunnel-ssh');
var config = {
username : 'myuser',
host: 'xxx:xxx:xxx:xxx',
privateKey:require('fs').readFileSync('id_rsa'),
port:22,
dstPort:27010,
localPort: 2000
};
var server = tunnel(config, function (error, server) {
if(error){
console.log("SSH connection error: " + error);
}
mongoose.connect('mongodb://127.0.0.1:2000/mysuperdb');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', function() {
console.log("DB connection successful");
});
});
Your ports aren't matching up. You have dstPort: 27010 but your connection string is 'mongodb://127.0.0.1:27017/mysuperdb'. One or the other needs to be corrected.

How to use Node.js to make a SSH tunneling connection to a MongoDB database

My credentials work perfectly with Robomongo but I can't make the connection with node.js
I have tried to make the connection using ssh2 and tunnel-ssh npm module and failed both times.
-The mongo connection does not require a password
-The ssh connection is made with a pem key
This is the code I've used with ssh2 module, I can establish the tunneling correctly but the mongo connection fails
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
//mongo connection
mongoose.connect('mongodb://localhost:27000/');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
console.log("database connection established");
var users = db.collection('user');
var getallUsers = function (date, callback){
users.find({}).toArray(function(err,data){
callback(data);
})
};
getallUsers(null, function (data){
console.log('data :'+ data);
});
});
//end of mongo connection
}).connect({
host: '**.**.**.**.**',
port: 22,
username: 'ec2-user',
privateKey: key
});
And the code the tunnel-ssh
var config = {
dstPort: 27000,
user: 'ec2-user',
host: '**.**.**.**.**',
privateKey: key
};
var server = tunnel(config, function (error, server) {
if(error){
console.log("SSH connection error: " + error);
}
console.log('database connection initalizing');
mongoose.connect('mongodb://localhost:27000/');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
console.log("database connection established");
var users = db.collection('user');
var getallUsers = function (date, callback){
users.find({}).toArray(function(err,data){
callback(data);
})
};
getallUsers(null, function (data){
console.log(data);
});
});
});
I'm not sure whether to use the regular MongoDB connection string after establishing the tunnel or referring to the database as localhost such as
mongodb://localhost:portnumber.
or
mongodb://databasepath.subpath.mongodbdns.com:27000
Localhost gives me a permission denied error, the latter gives me a timeout
As mscdex mentioned ssh2 isn't a good module to use to make an ssh tunnel connection to a database. tunnel-ssh is more appropriate.
Here are the configuration options I've used :
dstPort: remote database connection port
localPort: same as dstPort, It'll be the port you'll use for your local machine
username: SSH username,
host: SSH address
dstHost: database connection url (...mongodbns.com) ,
privateKey: SSH key
Then once your tunnel is connected connect via mongoose to your localhost such as mondodb://localhost:27000 (use the localport you defined in localPort)
var server = tunnel(config, function (error, server) {
if(error){
console.log("SSH connection error: " + error);
}
mongoose.connect('mongodb://localhost:27000/');
//...rest of mongoose connection
}
Since mongoose does not support passing in a stream to use as the underlying connection, you will have to listen on a local port (e.g. 27000) and forward incoming connections to that port over the ssh connection.
Fortunately there exists third party modules that build on ssh2 that provide this kind of functionality for you, such as tunnel-ssh. Try using one of those.
You can do it with official mongodb client for node
const sshTunnelConfig = {
agent: process.env.SSH_AUTH_SOCK,
username: 'ec2-user',
privateKey: require('fs').readFileSync('./path-to-ec2-key.pem'),
host: '3.98.174.12', //IP adress of VPS which is the SSH server
port: 22,
dstHost: 'docdb-cluster-vmabwxueb51y.eu-central-1.docdb.amazonaws.com',
dstPort: 27017,
localHost: '127.0.0.1',
localPort: 27018 //or anything else unused you want
};
const connectionProperties = {
sslValidate: true,
ssl: true,
sslCA: [fs.readFileSync('rds-combined-ca-bundle.pem')],
useNewUrlParser: true,
useUnifiedTopology: true,
authMechanism: 'SCRAM-SHA-1',
auth: {
user: 'docdbuser',
password: '<PASSWORD>'
},
tlsAllowInvalidHostnames: true,
tlsAllowInvalidCertificates: true,
};
tunnel(sshTunnelConfig, async (error, server) => {
if (error) {
console.log('SSH connection error: ', error);
}
const MongoClient = require('mongodb').MongoClient;
const client = MongoClient.connect('mongodb://localhost:27018/', propertiesConnection,
function(err, client) {
if(err)
throw err;
//Specify the database to be used
db = client.db('database-name');
//Specify the collection to be used
col = db.collection('collection-name');
//Insert a single document
col.insertOne({'hello':'Amazon DocumentDB'}, function(err, result){
//Find the document that was previously written
col.findOne({'hello':'Amazon DocumentDB'}, function(err, result){
//Print the result to the screen
console.log(result);
//Close the connection
client.close()
});
});
});
});
Because all the answers above didn't work for me for some reason, I am posting the code that worked for me. I'm tunneling from my Nodejs webserver to an PostgreSQL Database on an online ubuntu vm:
const SSH2Promise = require('ssh2-promise');
const {Client } = require('pg');
let config = {
host:process.env.SSH_HOST, //your machine IP-address like [193.xxx.xx.xxx]
port:process.env.SSH_PORT, //port you ssh to, probably 22
username: process.env.SSH_USERNAME, //username of your machine
privateKey: fs.readFileSync(path.join(__dirname, "../" + process.env.PRIVATE_KEY)) //your ssh private key to log in
};
function getDBConfig(port) {
return new Client({
user: process.env.DB_USER,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASS,
port: port,
});
}
async function makeDb(port) {
let dbClient = getDBConfig(port);
await dbClient.connect();
return {
async query(sql) {
return (await dbClient.query(sql)).rows;
}
};
}
const sshConn = new SSH2Promise(config);
let con;
(async function(){
await sshConn.connect();
console.log("Connection established");
let tunnel = await sshConn.addTunnel({remoteAddr: process.env.REMOTE_HOST, remotePort: process.env.REMOTE_PORT});
//Remote host: just use 127.0.0.1
//Remote port: port where your db is connected to ex: 5432
con = await makeDb(tunnel.localPort);
})();
//use connection like this:
await con.query("SELECT ... sql statement here);

Resources