如何使用 Node.js 建立到 MongoDB 数据库的 SSH 隧道连接

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

我的凭据与 Robomongo 完美配合,但我无法与 node.js
建立连接 我尝试使用 ssh2 和 tunnel-ssh npm 模块建立连接,但两次都失败了。
- mongo连接不需要密码
-ssh 连接是用 pem 密钥建立的

这是我与 ssh2 模块一起使用的代码,我可以正确建立隧道但 mongo 连接失败

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
});

以及 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);
        });

    });
});

我不确定是在建立隧道后使用常规 MongoDB 连接字符串还是将数据库引用为本地主机,例如
mongodb://localhost:portnumber.

mongodb://databasepath.subpath.mongodbdns.com:27000

Localhost给我一个权限被拒绝的错误,后者给我一个超时

由于 mongoose 不支持传入流以用作基础连接,您将必须侦听本地端口(例如 27000)并通过 ssh 连接将传入连接转发到该端口。

幸运的是,存在基于 ssh2 构建的第三方模块,可为您提供此类功能,例如 tunnel-ssh。尝试使用其中之一。

正如 mscdex 提到的,ssh2 不是用于建立到数据库的 ssh 隧道连接的好模块。 tunnel-ssh 更合适。

以下是我使用的配置选项:

dstPort:远程数据库连接端口

localPort:与 dstPort 相同,它将是您将用于本地计算机的端口

用户名:SSH 用户名,

主机:SSH 地址

dstHost: 数据库连接 url (...mongodbns.com) ,

privateKey:SSH 密钥

然后,一旦您的隧道连接通过猫鼬连接到您的本地主机,例如 mondodb://localhost:27000(使用您在 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
}

您可以使用官方 mongodb 节点客户端

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()
        });
      });
    });
  
});

由于上述所有答案出于某种原因对我都不起作用,所以我发布了对我有用的代码。我正在从我的 Nodejs 网络服务器隧道连接到在线 ubuntu vm:

上的 PostgreSQL 数据库
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);