0%

Raspberry Piをngrokで公開する - Part1: Expressをpm2から起動する

Raspberry Piで起動しているサービスにインターネットから直接アクセスしたい場合があります。開発中にプライベートネットワークのサーバーをトンネルしてリモートからテストするとき、ngrokを便利に使っています。同じやり方でRaspberry PiにNode.jsラッパーのnorokをインストールしてExpressのHello Worldをリモートから表示してみます。

ngrok 0.1.99

今回はnpmからインストールします。ngrokのバージョンは0.1.99です。norokはすでに2.x系がリリースされています。GitHubからcloneしてインストールすると2.xに対応したバージョンを使えます。

Node.js

node-armからdebパッケージをダウンロードしてNode.jsをインストールします。

$ wget http://node-arm.herokuapp.com/node_latest_armhf.deb
$ sudo dpkg -i node_latest_armhf.deb

プロジェクト

プロジェクトを作成します。作業したリポジトリはこちらです。

$ mkdir -p ~/node_apps/node-hello-ngrok-pm2
$ cd !$

package.json

package.jsonのひな形を作成しておきます。

~/node_apps/node-hello-ngrok-pm2/package.json
{
"name": "node-hello-ngrok-pm2",
"description": "node-hello-ngrok-pm2",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
}
}

ngrokExpressdotenvをインストールします。

$ npm install ngrok express dotenv --save

package.jsonのdependenciesにインストールしたパッケージが追記されました。

~/node_apps/node-hello-ngrok-pm2/package.json
{
"name": "node-hello-ngrok-pm2",
"description": "node-hello-ngrok-pm2",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"dotenv": "^1.2.0",
"express": "^4.13.3",
"ngrok": "^0.1.99"
}
}

ngrokのバイナリもnpmからインストールされます。バージョンを確認します。

$ ~/node_apps/node-hello-ngrok-pm2/node_modules/ngrok/bin/ngrok version
1.7

app.js

app.jsを作成します。Expressを起動してngrokで公開する単純なプログラムです。

~/node_apps/node-hello-ngrok-pm2/app.js
var ngrok = require('ngrok'),
express = require('express');

require('dotenv').load();
var app = express();

app.get('/', function(req, res) {
res.send('Hello World!');
});

var server = app.listen(process.env.EXPRESS_PORT, function() {
var host = server.address().address,
port = server.address().port;

console.log('listening at http://%s:%s', host, port);
ngrok.connect({
port: port
},
function (err, url) {
console.log(url);
});
});

Expressのポート番号は環境変数として.envに記述しておきます。

~/node_apps/node-node-hello-ngrok-pm2-pm2/.env
EXPRESS_PORT=3000

テストのため直接npm startを実行して起動します。

$ npm start

> node-hello-ngrok-pm2@0.0.1 start /home/pi/node_apps/node-hello-ngrok-pm2
> node app.js

listening at http://0.0.0.0:3000
https://26802xxx.ngrok.com

標準出力されたngrokのURLを使い、リモートからRaspberry PiのExpressにアクセスできるようになりました。

$ curl https://26802xxx.ngrok.com
Hello World!

pm2

pm2を使ってデモナイズします。npmパッケージはグローバルにインストールします。

インストール

$ sudo npm install pm2 -g

Raspberry Piの再起動後も、pm2に登録したプロセスが起動するようにinitスクリプトを作成します。

$ sudo env PATH=$PATH:/usr/local/bin pm2 startup -u pi
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Generating system init script in /etc/init.d/pm2-init.sh
[PM2] Making script booting at startup...
[PM2] -linux- Using the command:
su -c "chmod +x /etc/init.d/pm2-init.sh && update-rc.d pm2-init.sh defaults"
update-rc.d: using dependency based boot sequencing
[PM2] Done.
$ pm2 save
[PM2] Dumping processes

/etc/init.d/pm2-init.shが作成されました。エディタで開きPM2_HOMEを編集します。

/etc/init.d/pm2-init.sh
#export PM2_HOME="/root/.pm2"
export PM2_HOME="/home/pi/.pm2"

PM2_HOME/home/pi/.pm2に変更しないとinitスクリプトの起動時にエラーがでます。

$ sudo /etc/init.d/pm2-init.sh restart
Restarting pm2
fs.js:747
return binding.mkdir(pathModule._makeLong(path),
^
Error: EACCES, permission denied '/root/.pm2'
at Error (native)
at Object.fs.mkdirSync (fs.js:747:18)

プロセスの起動

pm2からサービスを起動します。

$ cd ~/node_apps/node-hello-ngrok-pm2
$ pm2 start app.js
[PM2] Starting app.js in fork_mode (1 instance)
[PM2] Done.
┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼────────────┼──────────┤
│ app │ 0 │ fork │ 2593 │ online │ 0 │ 0s │ 8.344 MB │ disabled │
└──────────┴────┴──────┴──────┴────────┴─────────┴────────┴────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app

標準出力されているngrokのURLを使って、curlからアクセスします。

$ pm2 logs --lines 2 app
[PM2] Tailing last 2 lines for [app] process

app-0 (out): listening at http://0.0.0.0:3000
app-0 (out): https://2724bxxx.ngrok.com
$ curl https://2724bxxx.ngrok.com
Hello World!

restart

initスクリプトからpm2を再起動したあとのアプリの起動をテストします。

$ sudo /etc/init.d/pm2-init.sh restart
Restarting pm2
[PM2] Dumping processes
[PM2] Deleting all process
[PM2] deleteProcessId process id 0
┌──────────┬────┬──────┬─────┬────────┬─────────┬────────┬────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
└──────────┴────┴──────┴─────┴────────┴─────────┴────────┴────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
[PM2] Stopping PM2...
[PM2][WARN] No process found
[PM2] All processes have been stopped and deleted
[PM2] PM2 stopped
Starting pm2
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Resurrecting
Process /home/pi/node_apps/node-hello-ngrok-pm2/app.js launched
┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ app │ 0 │ fork │ 2779 │ online │ 0 │ 0s │ 13.176 MB │ disabled │
└──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app

logからngrokのURLを出力します。

$ pm2 logs --lines 2 app
[PM2] Tailing last 2 lines for [app] process

app-0 (out): listening at http://0.0.0.0:3000
app-0 (out): https://2724bxxx.ngrok.com

リモートからRaspberry PiのExpressにアクセスできました。

$ curl https://2724bxxx.ngrok.com
Hello World!

最後にOSをrebootした後もサービスが起動していることを確認しておきます。

$ sudo reboot