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

Posted

技术标签:

【中文标题】如何使用 Node.js 建立与 MongoDB 数据库的 SSH 隧道连接【英文标题】:How to use Node.js to make a SSH tunneling connection to a MongoDB database 【发布时间】:2016-11-25 09:16:22 【问题描述】:

我的凭据与 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
);

还有隧道 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 连接字符串还是将数据库称为 localhost,例如 mongodb://localhost:portnumber. 或 mongodb://databasepath.subpath.mongodbdns.com:27000

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

【问题讨论】:

【参考方案1】:

正如 mscdex 提到的,ssh2 不是一个用于建立与数据库的 ssh 隧道连接的好模块。隧道 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

【讨论】:

我得到了这个>> 错误:所有配置的身份验证方法都失败 注意:我正在使用 require('mongodb').MongoClient ,require('tunnel- ssh'),var config = 用户名:'root',密码:'xxxxxx',主机:“xx11.130”,dstHost:“xx11.130”,端口:22,dstHost:url,dstPort:10945,localPort:10945 ; 仅供参考,tunnel-ssh 内部使用 ssh2 建立隧道【参考方案2】:

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

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

【讨论】:

感谢回复我也花了很多时间在隧道 ssh 上,我无法连接它,我的隧道 ssh 代码在上面。 您是否尝试在配置对象中使用username 而不是user【参考方案3】:

你可以用官方的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()
        );
      );
    );
  
);

【讨论】:

感谢您分享这些代码,但您确定该块运行良好吗?我试图做同样的事情。 SSH 连接没问题,但之后,我无法连接 mongo 客户端。我尝试使用您的示例代码并再次尝试。 propertiesConnection 与 connectionProperties 没有意义....这是否经过测试? sshTunnelConfig 对象的属性似乎与tunnel-ssh 的接口相匹配。以下 q/a 应该更有助于使其正常工作:***.com/questions/40903566/…【参考方案4】:

由于某些原因,上述所有答案都对我不起作用,因此我发布了对我有用的代码。我正在从我的 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);

【讨论】:

以上是关于如何使用 Node.js 建立与 MongoDB 数据库的 SSH 隧道连接的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 mongoose 将本地 mongodb 与 node.js 应用程序连接?

javascript 如何将MongoDB与Node.js一起使用

如何将 Mongoose/Mongodb 与 node.js- 护照身份验证一起使用

Node.js + MongoDB 全局变量和作用域

Node.js /Express 和 mongoose:通过自动拉取新数据建立“可观察”的 mongodb 连接?

如何让 node.js 使用 mongoose 连接到 mongolab