ngrokを使ってローカル環境を外部に公開する

はじめに

ngrokを最近知って、ちょっと使ってみたいなと思ったので実践をする。

環境

Windows 11 Professional
Docker Desktop 4.34.1 (166053)

準備

  • ngrokアカウントの取得
  • ローカル環境で適当なWebサーバを立てる

ngrokアカウントの取得

  1. ngrokSign upを選択する。
  2. Sign up with GitHub で、GitHubアカウントを使って登録する。
    ※ここはお好みで
  3. 出てくる内容に従って進めていき、ダッシュボードの表示まで行けば完了。
dashboard-01.png

ローカル環境で適当なWebサーバを立てる

例によって、Dockerで構築をする。

compose.ymlを以下のように作成して、docker compose up -dで立ち上げる。

services:
  web:
    image: nginx:1.27.1
    ports:
      - 80:80

localhostで下記の画面になっていればOK.

nginx-01.png

ngrokを導入する

今回は、Dockerを利用しているので https://hub.docker.com/r/ngrok/ngrok のイメージを利用して実践をする。

https://ngrok.com/docs/getting-started/ を見てみると、

  1. ngrokエージェントをインストール
  2. ngrok authtokenを設定
  3. ngrokを起動

上記で設定できるようだ。

Dockerで設定する場合は以下を見ればよさそうだ。
https://ngrok.com/docs/using-ngrok-with/docker/

compose.ymlにngrokのサービスを追加

バージョンは、現時点で最新の 3.15.0を使用する。
イメージはngrok/ngrok:3.15.0-debian とした。

services:
  web:
    image: nginx:1.27.1
    ports:
      - 80:80
  ngrok:
    image: ngrok/ngrok:3.15.0-debian
    restart: unless-stopped
    command:
      - "start"
      - "--all"
      - "--config"
      - "/etc/ngrok.yml"
    volumes:
      - ./ngrok.yml:/etc/ngrok.yml
    ports:
      - 4040:4040

Using ngrok with Docker Composeに沿って、構築をした。
バージョンの指定だけ自我を入れた。

ngrok.ymlの作成

ngrok.ymlcompose.ymlと同じ階層に作成をする。

https://ngrok.com/docs/http/
https://ngrok.com/docs/agent/config/v3/ をもとに作成をする。

version: "3"
agent: 
  authtoken: [取得したauthtokenを入力]
endpoints:
  - name: web
    upstream:
      url: http://web:80
      protocol: http

動作確認

  1. Dockerのビルド&コンテナの立ち上げ
docker compose up -d --build
  1. http://localhost:4040/ にアクセスをして、公開URLを取得する。
publish-01.png
  1. 公開URLにアクセスをすると、ngrokのページが出てくるので「Visit Page」でページ遷移をする。
publish-02.png
  1. nginxのスタートページ(ローカルと同じ)が表示されていればOK
publish-03.png

補足:エラー内容

ngrok.ymlurlを間違えている

webとしてコンテナを定義しているのに、nginxと誤った名前でurlを記載してしまったため下記のエラーが発生した。
このようなエラー画面になる。
mistake-url-01.png

※わかりやすくエラーが書いてあるのでありがたい。

ローカル環境で対応していないhttp2プロトコルで接続しようとしている

http2upstreamprotocolに指定していたが、ローカル環境ではhttpsでの接続は許可していないので使用できない。

このようなエラー画面になる。
mistake-protocol-01.png

おまけ: ngrokの動作の理解をしたい

ngrokを起動してから、公開されるまでの流れの細部を知りたいので少し調べた。
まずは、公式ドキュメントにある下記を読んだ。
https://ngrok.com/docs/how-ngrok-works/

最初に疑問となったのは、接続の確立の仕方である。
一般的なPCであればファイアウォールがあるので、どうやってインターネットからローカル環境にアクセスできるのだろうと思った。
どうやら、ローカルのエージェントから ngrokクラウドサーバに接続をしに行って、データのやり取りをするTLSのトンネルを作成することで実現しているようだ。

Unlike traditional reverse proxies, ngrok does not transmit traffic to your upstream services by forwarding to IP addresses. Instead, you run a small piece of software alongside your service that we call an agent which connects to ngrok’s global service via secure, outbound persistent TLS connections. When traffic is received on your endpoints at the ngrok edge, it is transmitted to the agent via those TLS connections and finally from the agent to your upstream service.

の部分で説明がされている。

エージェントをローカルで実行し、TLS接続を介してngrokのサーバとやり取りするようだ。
上記から、ファイアウォールのアウトバウンド接続で、ngrokで使用するポートが拒否されていたりすると、恐らく使用できないのだと思われる。
この点は注意が必要そうだ。

ローカルで起動→公開してアクセスするまでの流れをシーケンス図にまとめてみたので、下記のような理解でよいのだろう。

sequenceDiagram
    participant User as 開発者
    participant ngrokLocal as ngrokローカルエージェント
    participant ngrokCloud as ngrokクラウドサーバー
    participant LocalServer as ローカルサーバー
    participant Client as 外部クライアント

    User->>ngrokLocal: ngrok起動とポート指定 (例: 80)
    ngrokLocal->>ngrokCloud: トンネル接続リクエスト送信
    ngrokCloud-->>ngrokLocal: 公開URLの生成と通知 (例: https://abcdef.ngrok.io)

    Client->>ngrokCloud: 公開URLにリクエスト送信 (例: https://abcdef.ngrok.io)
    ngrokCloud->>ngrokLocal: リクエストをトンネル経由で転送
    ngrokLocal->>LocalServer: ローカルサーバーにリクエストを転送
    LocalServer-->>ngrokLocal: レスポンスを返す
    ngrokLocal-->>ngrokCloud: トンネルを通してレスポンスを返す
    ngrokCloud-->>Client: クライアントにレスポンスを返す

ローカルエージェントからngrokクラウドサーバまではTLS接続で暗号化されているので、この点は盗聴の対策などもできている。

参考

おわりに

ngrokというサービスを最近知ったので使用してみた。
ローカル環境を外部に公開できるは便利かと思ったが、業務だと大体のケースでテスト環境を作成しているのでどういうケースで使うかは考えてみたい。
作ったサービスをサーバを立てずにサクッとみてもらいたいというときには便利そうだ。
ただ、その場合のセキュリティ担保をどうするかについては、ngrokのドキュメントとか読んでみればわかるのだろうか、今後の課題としよう。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。