最近では、HTTPサーバを立ち上げるにも、HTTPSでないとChromeでエラーとなったり、他のWebAPIと連携することができない場面が多くなってきました。また、SSL証明書もオレオレ証明書ではだめで、正規のSSL証明書である必要があったりします。
さらに、HTTPSであったとしても、ポート番号が443である必要がある場面が増えてきました。単に、静的なWebコンテンツであれば、GitHubにコンテンツをアップして、GitHub Pagesの機能を使って公開することはできるのですが、Node.js等を使ったWebAPIはできなかったりします。
そこで、ngrokを使うことで、ローカルに立ち上げたHTTPサーバを、正規のSSL証明書でかつポート番号443で公開することができ、WebAPIサーバとしても振舞えるようにします。
ngrokアカウントの作成
まだの場合は、ngrokアカウントを作成します。以下のページからSign upします。
作成済みの場合は、Loginします。
ngrokのダウンロード
ngrokを動作させるOSに合わせてバイナリをダウンロードします。
今回は、Intel CPUのUbuntuで動作させます。現時点では「ngrok-v3-stable-linux-amd64.tgz」でした。
これを解凍すると、実行形式のngrok ができます。
今回は、以下の場所に置きます。
~/ngrok/ngrok
ngrokの実行準備
ngrokを実行するには、Authtokenが必要です。ngrokログインアカウントごとに払い出されています。ngrokにLoginして、左側のナビゲータから「Your Authtoken」を選択すると表示されます。
次に、ngrokを実行する前に、これをngrokを実行する予定のOSユーザに設定します。
実行したいOS上で、ngrokを実行する予定のユーザで、以下を実行します。
> ~/ngrok/ngrok config add-authtoken [Authtoken]
これにより、OSユーザのホームディレクトリの下に「~/.config/ngrok/ngrok.yml」というファイルが出来上がり、そこに先ほどのAuthtokenが書き込まれます。
HTTPサーバの立ち上げ
それではさっそくHTTPサーバを立ち上げましょう。
今回は簡単に、以下を利用します。
ZIPでダウンロードして、解凍し、必要なモジュールをインストールします。
> unzip amplify_template-master.zip
> cd amplify_template-master
> npm install
次に、.envファイルを作成して、ローカルで立ち上げたいHTTPのポート番号を指定します。たとえば、30080で立ち上げたい場合は以下のようにします。
PORT=30080
以下のようにすることで、HTTPサーバが立ち上がります。
> node app.js
ブラウザで開いてみます。
http://[HTTPサーバを立ち上げたホスト名]:30080
以下のファイルが表示されます。
amplify_template-main/public/index.html
ngrokを立ち上げる
HTTPSでアクセスできるように、ngrokを立ち上げます。以下のように実行します。
> ~/ngrok/ngrok http 30080
ngrok (Ctrl+C to quit)
Session Status online
Account XXXXXXXX@gmail.com (Plan: Free)
Version 3.0.2
Region Japan (jp)
Latency calculating...
Web Interface http://127.0.0.1:4040
Forwarding https://XXXX-XXXX-XXXX-XXX-XXXX-XXXX-XXX-XXXX-XXXX.jp.ngrok.io -> http://localhost:30080
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
これでHTTPSでアクセスできるようになっています。上記のForwardingで表示されているURLにアクセスしてみましょう。
HTTPSのURLを取得表示
実は、HTTPSでアクセスできるURLは、ngrokの起動のたびに異なります。(有償プランのngrokであれば、固定にはできますが。。。)
そこで、HTTPSのURLがわかるようにします。
HTTPSのURLは以下のURLに対してHTTP Getすると得られる文字列の中にあります。
curl http://localhost:4040/api/tunnels
{
"tunnels": [
{
"name": "command_line",
"ID": "XXXXXXXXXXXXXXXXXXXXXXX",
"uri": "/api/tunnels/command_line",
"public_url": "https://XXXX-XXXX-XXXX-XXX-XXXX-XXXX-XXX-XXXX-XXXX.jp.ngrok.io",
"proto": "https",
"config": {
"addr": "http://localhost:30080",
"inspect": true
},
"metrics": {
"conns": {
"count": 4,
"gauge": 0,
"rate1": 0.007181222997985889,
"rate5": 0.008537526897585294,
"rate15": 0.0038307014878300348,
"p50": 6853040947.5,
"p90": 8925784161,
"p95": 8925784161,
"p99": 8925784161
},
"http": {
"count": 19,
"rate1": 0.03054120171725377,
"rate5": 0.03966522214651725,
"rate15": 0.018062001948772572,
"p50": 3123538,
"p90": 7467821,
"p95": 7900887,
"p99": 7900887
}
}
}
],
"uri": "/api/tunnels"
}
public_url のところにあります。
このエンドポイントは、ローカルホストからしか呼び出せないようです。
そこで、立ち上げたHTTPサーバで、WebAPIを実装し、その中でローカルホストに対してHTTP Getします。
以下のようにフォルダを作成して、swagger.yamlとindex.jsを作成します。
> mkdir amplify_template-main/api/controllers/tunnels
> cd amplify_template-main/api/controllers/tunnels
> vi swagger.yaml
> vi index.js
paths:
/tunnels:
get:
responses:
200:
description: Success
schema:
type: object
'use strict';
const HELPER_BASE = process.env.HELPER_BASE || "/opt/";
const Response = require(HELPER_BASE + 'response');
const fetch = require('node-fetch');
const Headers = fetch.Headers;
const { URL, URLSearchParams } = require('url');
exports.handler = async (event, context, callback) => {
var response = await do_get('http://localhost:4040/api/tunnels');
return new Response({ public_url: response.tunnels[0].public_url } );
};
function do_get(url, qs) {
var params = new URLSearchParams(qs);
var params_str = params.toString();
var postfix = (params_str == "") ? "" : ((url.indexOf('?') >= 0) ? ('&' + params_str) : ('?' + params_str));
return fetch(url + postfix, {
method: 'GET',
})
.then((response) => {
if (!response.ok)
throw 'status is not 200';
return response.json();
});
}
これで、ポート番号30080で立ち上げたHTTPサーバにおいて、/tunnelsというエンドポイントでpublic_urlが返ってくるようになりました。
これを、HTTPサーバの静的ページから/tunnelsのエンドポイントをたたいてpublic_urlを取得して、静的ページに表示させるようにします。
以下のファイルを書き換えます。Vue 2.0を使っています。
amplify_template-main/public/index.html
amplify_template-main/public/js/start.js
以下、抜粋です。
<div id="top" class="container">
<h1>Template</h1>
<label>public_url</label> <a v-bind:href="public_url">{{public_url}}</a>
<!-- for progress-dialog -->
<progress-dialog v-bind:title="progress_title"></progress-dialog>
</div>
data: {
public_url: ""
},
・・・・
mounted: function(){
proc_load();
do_get('/tunnels')
.then(response =>{
this.public_url = response.public_url
});
}
それでは、HTTPサーバを立ち上げなおして、Webページを開いてみます。
> node app.js
もう一度、ブラウザで以下を開きます。
http://[HTTPサーバを立ち上げたホスト名]:30080
そうすると、public_urlの後に、HTTPSのURLが表示されています。それをクリックすることで、HTTPSでのアクセスに切り替わります。同じページを表示しているため、違いはないですが、アドレスバーの表示がHTTPSの表示に切り替わり、錠のマークがついているので、ちゃんとHTTPSになっていることがわかります。
自動起動させる
後はこれを自動起動させます。
HTTPサーバの起動にはpm2を利用し、ngrokの起動にはSystemdを利用します。
~/pm2/pm2.config.js
module.exports = {
apps : [
{
name: "Public_Sites(30080)",
script: "./app.js",
cwd: '/home/XXXX/amplify_template-master'
}
]
}
pm2については、以下を参考にしてください。
次に、ngrokを起動するためのスクリプトファイルを作成します。作成場所はどこでもよいです。以下は例です。
~/project/cron/ngrok-startup.sh
#!/bin/sh
/home/XXXX/ngrok/ngrok http 30080
そして、実行権限を与えます。
> chmod +x ngrok-startup.sh
ngrokのためのsystemd設定ファイルは以下のようになります。
# vi /etc/systemd/system/ngrok-XXXX.service
以下のUserのところに、ngrokを起動させるOSアカウント名を記載します。
[Unit]
Description=ngrok startup
After=network.target
ConditionPathExists=/home/XXXX/projects/cron
[Service]
ExecStart=/home/XXXX/projects/cron/ngrok-startup.sh
Restart=no
Type=simple
User=XXXX
[Install]
WantedBy=multi-user.target
以下のようにして、Systemdで起動させます。
> systemctl restart ngrok-XXXX.service
起動したかどうかは、以下で確認できます。
> systemctl status ngrok-XXXX.service
● ngrok-XXXX.service - ngrok startup
Loaded: loaded (/etc/systemd/system/ngrok-XXXX.service; disabled; vendor preset: enabled)
Active: active (running) since Wed 2022-04-20 22:11:17 JST; 24min ago
Main PID: 6643 (ngrok-startup.s)
Tasks: 10 (limit: 4261)
CGroup: /system.slice/ngrok-XXXX.service
tq6643 /bin/sh /home/XXXX/projects/cron/ngrok-startup.sh
mq6648 /home/XXXX/ngrok/ngrok http 30080
Apr 20 22:11:17 compact systemd[1]: Started ngrok startup.
以上