LoginSignup
9
5

More than 1 year has passed since last update.

ngrokでローカルに立ち上げたHTTPサーバをHTTPSで公開する

Last updated at Posted at 2022-04-20

最近では、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」を選択すると表示されます。

image.png

次に、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で立ち上げたい場合は以下のようにします。

amplify_template-master/.env
PORT=30080

以下のようにすることで、HTTPサーバが立ち上がります。

> node app.js

ブラウザで開いてみます。

http://[HTTPサーバを立ち上げたホスト名]:30080

以下のファイルが表示されます。
amplify_template-main/public/index.html

image.png

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
amplify_template-main/api/controllers/tunnels/swagger.yaml
paths:
  /tunnels:
    get:
      responses:
        200:
          description: Success
          schema:
            type: object
amplify_template-main/api/controllers/tunnels/index.js
'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

以下、抜粋です。

amplify_template-main/public/index.html
    <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>
amplify_template-main/public/js/start.js
    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

image.png

そうすると、public_urlの後に、HTTPSのURLが表示されています。それをクリックすることで、HTTPSでのアクセスに切り替わります。同じページを表示しているため、違いはないですが、アドレスバーの表示がHTTPSの表示に切り替わり、錠のマークがついているので、ちゃんとHTTPSになっていることがわかります。

自動起動させる

後はこれを自動起動させます。

HTTPサーバの起動にはpm2を利用し、ngrokの起動にはSystemdを利用します。

~/pm2/pm2.config.js

~/pm2/pm2.config.js
module.exports = {
  apps : [
  {
          name: "Public_Sites(30080)",
          script: "./app.js",
          cwd: '/home/XXXX/amplify_template-master'
  }
  ]
}

pm2については、以下を参考にしてください。

 pm2でNode.js実行環境を整備する

次に、ngrokを起動するためのスクリプトファイルを作成します。作成場所はどこでもよいです。以下は例です。

~/project/cron/ngrok-startup.sh

~/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アカウント名を記載します。

/etc/systemd/system/ngrok-XXXX.service
[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.

以上

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5