前置き
Webサーバーを開発するとき、別のサービスから変化があった時にPushを受け取りたいことがあります。
例えば、Google Drive APIにはPush Notificationsという機能があり、予め外部からアクセスできるURLをGoogleのサーバに登録しておくことで、ファイルに変化があったらそのURLを呼び出してくれるというものです。
でもそのためには外部に公開されているURLが必要。
開発効率を考えたら、少しコードを変更して、サーバにデプロイ→修正→繰り返し、、、とか、メンドイ。手間。ヤダ。
そこでSSHポートフォファードを使って、サーバーで受け取ったHTTP GETをローカルのHTTPサーバに転送します。
HTTPサーバ (ローカル)
まずはローカルでHTTPサーバを動かしてください。Apacheでもなんでもいいです。
私は手抜きなので、node.jsで以下の簡単なHTTPサーバを動かします。
var express = require('express');
var app = express();
app.get('/*', function (req, res) {
return res.send("now : " + ((new Date()).toString()));
});
var port = 20000;
console.log("Start listening the port at " + port);
app.listen(port);
ちゃんと http://localhost:20000 でアクセスできることを確認しましょう。
リモートSSHポートフォファード
サーバー内で3000番ポートにアクセスしたら、ローカルの20000番ポートに転送されるようにします。
ポート番号を変えているのは説明の上で、どことどこのポートがつながっているか、分かりやすくするためだけです。
sshのリモートポートフォファード(-Rオブプション) を No command(-N -C)でバックグラウンド(-f)で実行します。
local $> ssh -f -N -C -i ~/.ssh/id_rsa -R 3000:localhost:20000 admin@myserver.com
これでSSHサーバー内から http://localhost:3000 にアクセスしたらブラウザに表示されるはずです。
もちろん、curlでもいいです。
server $> curl localhost:3000
now : Wed Nov 11 2015 08:15:34 GMT+0900 (JST)
でもこれだとローカルから http://myserver.com:3000 にアクセスしても表示されないはず。
なぜかというとリモートSSHポートフォファードは、接続した先のコンピューターからのアクセスしか受け付けないから。
つまりブラウザから http://myserver.com:3000 は外部から接続しているので、転送されないわけです。
サーバー内でローカルSSHポートフォファード
サーバの外部からアクセスをサーバー内の3000番ポートに転送する必要があります。
そこで、myserver.comの3001番をmyserver.com:3000番に転送します。
このときに**-gオプション**を付けると、外部からのアクセスも許可するようになります。gはglobalですね。
server $> ssh -f -N -C -g -L 3001:localhost:3000 admin@localhost
サーバーにログインしたくなければ、下記でも出来ます。
local $> ssh -f -i ~/.ssh/id_rsa admin@myserver.com -t ssh -f -N -C -g -L 3001:localhost:3000 admin@localhost
こうすれば、どこからでもブラウザで http://myserver.com:3001 とすれば表示されるはずです。
SSH-Agentを使えば、この2行だけ。
-A
はSSH-Agentを使うオプションです。
SSH-AgentはIdentityファイルをキャッシュしてくれるサービスで、Macなら標準でインストールされているはず。
local $> ssh -f -N -C -A -R 3000:localhost:20000 admin@myserver.com
local $> ssh -A -f admin@myserver.com -t ssh -f -N -C -g -L 3001:localhost:3000 admin@localhost
当然ですけど
外部向けのポート(例では3001番)はファイヤーウォールで開けておかないと、サーバーにはアクセスできません。
ちなみに
今回はローカル上でHTTPサーバーだったが、FTPでもProxyServerでもできます。