エロサイトの作り方

2013年11月から勉強しながらエロサイトを作っています。

Node.jsでSSHポート転送を使ってリモートのMongoDBに接続する方法

たまに手元のコードでサーバーのDBを使いたいことがあるのだけど、そのためにサーバーのポートを開けるのはちょっと…と思うので、SSHのポート転送を使って接続する方法を実装してみました。

といっても、SSHコマンド呼んでいるだけですが。

ソース

'use strict';

var exec     = require('child_process').exec;
var async    = require('async');
var sprintf  = require('sprintf').sprintf;
var mongodb  = require('mongodb');

async.waterfall([

    // 接続情報
    function(next) {
        var info = {
            localName:  'localhost', // これはlocalhost固定でいいと思う
            localPort:  27717,       // ローカルでもMongDBを立ち上げているので、ポートを変えている
            serverName: 'sakura',    // 接続先のサーバー名。./ssh/configファイルのHostの値
            serverPort: 27017,       // サーバー側のポート名。MongoDBデフォルトなら27017
            database:   'test'       // 接続するデータベース名
        };
        next(null, info);
    },

    // SSHポート転送
    function(info, next) {
        var cmd = sprintf('ssh -24N -L %d:%s:%d %s', info.localPort, info.localName, info.serverPort, info.serverName);
        console.log('exec:', cmd);

        info.ssh = exec(cmd);

        // 接続されるまで少し待つ
        setTimeout(function() {
            next(null, info);
        }, 5000);
    },

    // MongoDB接続
    function(info, next) {
        var url = sprintf('mongodb://%s:%d/%s', info.localName, info.localPort, info.database);
        console.log('connect:', url);

        mongodb.MongoClient.connect(url, function(err, db) {
            next(err, info, db);
        });
    },

    // なんかの処理
    function(info, db, next) {
        var admin = new mongodb.Admin(db);
        admin.buildInfo(function (err, buildInfo) {
            console.log('MongoDB version:', buildInfo.version);
            next(err, info, db);
        });
    },

    // MongoDB切断
    function(info, db, next) {
        db.close(function(err) {
            next(err, info);
        });
    }

], function(err, info) {
    if (err) {
        console.log(err, err.stack);
    }

    // SSH切断
    if (info) {
        info.ssh.kill();
    }
});

実行結果

exec: ssh -24N -L 27717:localhost:27017 sakura
connect: mongodb://localhost:27717/test
MongoDB version: 2.4.5

欠点

  • エラーで落ちるとポートが開いたままになる
    • process.on('SIGTERM')process.on('uncaughtException')で終了処理を入れれば大丈夫かなぁ…
  • 複数のプログラムでポートがかぶると、接続時はスルーされるが、先に終わったものが一気に切断してしまう
    • 対応するにはnode-portscanner等を使って、ポートが被らないようにしないといけない