- 技術 💻
ngrokとは|使い方・料金・Webhook受信とエラーの直し方
結論
ngrokとは、手元のPCで動くアプリにインターネットから届くHTTPSのURLを付けるサービスです。読み方は「エングロック」です。
この記事でわかること
- 始め方4ステップとコマンド早見表8項目
- Webhookの署名検証・重複除外の受信ログ
- 無料枠の上限7項目と代替4種との違い表
手元で ngrok エージェントを起動すると、エージェントが ngrok のクラウドへ外向きに接続し、公開 URL に来たリクエストを同じ接続で手元のアプリへ届けます。
flowchart TD
U[ブラウザ・Webhookの送り手] -->|https の公開URL| C[ngrok クラウド]
A[ngrok エージェント<br>手元のPC] -->|外向きの TLS 443 で接続| C
C -->|同じ接続で届ける| A
A --> L[手元のアプリ<br>localhost:8080]
よく使うコマンドを先にまとめます。
| やりたいこと | コマンド | 補足 |
|---|---|---|
| 手元の 8080 番を公開する | ngrok http 8080 |
無料の dev domain が付く |
| authtoken を登録する | ngrok config add-authtoken トークン |
最初に1回だけ |
| 届いたリクエストを見る | ブラウザで http://localhost:4040 |
Replay で再送もできる |
| HTTPS で動くアプリを公開 | ngrok http https://localhost:8443 |
ERR_NGROK_3004 の対策 |
| 認証をかけて公開する | ngrok http 8080 --traffic-policy-file policy.yml |
Basic 認証・OAuth・IP 制限 |
| 設定ファイルを確かめる | ngrok config check |
場所も表示される |
| 設定ファイルで起動する | ngrok start 名前・ngrok start --all |
複数をまとめて起動 |
| 版を見る・更新する | ngrok version・ngrok update |
最新は 3.39.12 |
確認環境:ngrok エージェントの仕様・コマンド・設定ファイル・エラー文は、ngrok 公式ドキュメント(ngrok.com/docs と、その原稿の GitHub リポジトリ ngrok/ngrok-docs の 2026年10月21日の版。エージェントの最新版は変更履歴で 3.39.12)で、料金は ngrok の料金ページで確かめました。Webhook を受けるローカルのサーバーは Ubuntu 24.04.4・Python 3.11.15(標準ライブラリのみ)で作り、GitHub と同じ形の署名付きリクエストを自作のスクリプトで送って受信ログ・署名検証・重複の除外を確かめました。公開 URL の Host ヘッダーで起きるエラーは Vite 8.3.5(Node.js 22.22.2)と Django 5.2.18 に curl 8.5.0 で送って再現し、直る様子まで確かめています。代替サービスは Cloudflare・localhost.run・Tailscale・VS Code の公式ドキュメントで確かめました(確認日 2026年10月22日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「ngrokとは|使い方・料金・Webhook受信とエラーの直し方」
ngrokとは(読み方・何ができるか)
この節では、ngrok が何をするサービスで、どんな場面で使うかが分かります。
ngrok(エングロック)は、ローカル(手元のPC)で動いている Web アプリや API に、インターネットからアクセスできる HTTPS の URL を付けるサービスです。 公式 FAQ には、読み方は「en-grok」、最初の試作は 2013年3月20日とあります。現在の ngrok は、公式ドキュメントで「アプリ・API・AI モデルへの通信を届けて守る、開発者向けのインフラ」と紹介され、API ゲートウェイや Kubernetes の入口としても使えますが、いちばんよく使われるのは「localhost を一時的に外へ見せる」用途です。
1Webhook の受信テスト
GitHub・Stripe・LINE などの Webhook は、インターネット上の URL にしか送れません。ngrok の URL を登録すると、手元のサーバーで受けてデバッグできます。
2スマホ・他の人に見せる
作りかけの画面を、デプロイせずにスマホの実機や離れた場所の人に見せられます。URL は HTTPS なので、HTTPS が必要なブラウザの機能も試せます。
3リクエストの中身を見る
届いたリクエストとレスポンスを localhost:4040 の画面で見られ、同じリクエストをボタン1つで送り直せます。
ポート開放やルーターの設定をせずに使えるのが特徴です。理由は次の「仕組み」の節で見ます。
ngrokの仕組み(なぜ外から手元のPCに届くのか)
この節では、ポートを開けていないのに外から届く理由と、エージェントを止めると何が起きるかが分かります。
公式ドキュメント「How ngrok Agents Work」の説明をまとめると、次の3つです。
- エージェントは起動すると、ngrok へ外向きに、ポート 443 の TLS(暗号化された接続)を張ります。 これを「セッション」と呼びます。
- セッションの上に「エンドポイント」(公開 URL)を作ります。 エンドポイントに来た通信は、セッションを通ってエージェントに届き、エージェントが手元のアプリ(上流、upstream)へ渡します。
- 手元のPCは、外からの接続を待ち受けません。 そのため NAT(家庭のルーター)や会社のファイアウォールの内側でも動き、ポート転送も受信用のファイアウォールの規則も要りません。
| 言葉 | 意味 | 例 |
|---|---|---|
| エージェント | 手元で動かす ngrok のプログラム | ngrok コマンド |
| セッション | エージェントと ngrok の間の、外向きの TLS 接続 | ポート 443 |
| エンドポイント | 外から来る通信を受ける URL | https://名前.ngrok-free.app |
| 上流(upstream) | エージェントが通信を渡す先 | http://localhost:8080 |
| authtoken | エージェントが自分のアカウントを名乗るための鍵 | ダッシュボードで発行 |
| Traffic Policy | ngrok 側で認証・書き換えなどを行う規則 | Basic 認証・OAuth・IP 制限 |
エンドポイントはセッションの上にあるので、エージェントを止めると URL も応答しなくなります。 止まっている URL を開くと ERR_NGROK_3200(The endpoint is offline.)になります。常に動かしたいときは、公式ドキュメントでは OS のサービスとして動かす(ngrok service)、複数のエージェントで同じ URL を受ける(endpoint pooling)などの方法が案内されています。
自分で同じことをするなら、SSH のリモートポート転送(ssh -R)でも「外のサーバーから手元へ」の通り道を作れます。ngrok も ssh -R で使う方法(SSH Reverse Tunnel)を用意していますが、公式ドキュメントはエージェントか SDK が使えないときだけの手段としています。
ngrokの料金と無料プランの制限(2026年10月22日時点)
この節では、無料でどこまで使えるか、有料にすると何が変わるかが分かります。
ngrok の料金ページと公式ドキュメント「Free Plan Limits」「Pricing and Limits」で確かめた、2026年10月22日時点のプランです。
| プラン | 月額 | 主な内容 |
|---|---|---|
| Free | 0ドル | 1回限りの5ドル分の利用枠、オンラインのエンドポイント3つまで、データ転送1GB、HTTP/S リクエスト2万回、警告ページあり、dev domain 1つ |
| Hobbyist | 10ドル(年払いで24ドル安くなる) | 毎月10ドル分の利用枠、データ転送5GB、リクエスト10万回、警告ページなし、ngrok のドメインを10個まで |
| Pay-as-you-go | 20ドル+超過分 | 毎月20ドル分の利用枠、エンドポイント無制限、独自ドメイン、ユーザー3人(以降1人5ドル) |
| Enterprise | 個別見積もり | SSO/SAML・SLA・契約や請求書払いなど |
Pay-as-you-go の超過分の単価は、ドキュメントの表ではデータ転送が5GBを超えると1GBあたり0.10ドル、HTTP リクエストが10万回を超えると10万回あたり1ドルです。
無料プランの上限
公式ドキュメントの無料プランの上限を、種類ごとに並べます。
| 種類 | 項目 | 無料プランの上限 |
|---|---|---|
| 月の上限 | データ転送(送り出し) | 1GB |
| 月の上限 | HTTP リクエスト | 20,000 回 |
| 月の上限 | TCP 接続 | 5,000 回 |
| 月の上限 | Webhook の署名検証 | 500 回 |
| 速さの上限 | HTTP リクエストの速さ | 毎分 4,000 回 |
| 同時の上限 | オンラインのエンドポイント・同時のエージェント | 3・3 |
| 同時の上限 | ユーザー・dev domain | 1・1 |
ドキュメントにある、無料プランで知っておきたい点です。
- 無料のエンドポイントに時間制限はありません。 2026年10月22日時点のドキュメントには「タイムアウトは無く、いつまでもオンラインにできる」とあり、続けて動かすなら OS のサービスとして動かすよう案内しています。
- ブラウザでの表示の前に、警告ページ(interstitial)が出ます。 訪問者が「Visit」を押すと、そのドメインでは7日間出なくなります。API やプログラムからの呼び出しには影響しません(詳しくは「エラー一覧」の ERR_NGROK_6024)。
- TCP のエンドポイントは、無料でもクレジットカードの登録が要ります。 公式 FAQ では、悪用を防ぐためで、カードには請求しないとしています。
- ダッシュボードの Traffic Inspector の保存期間は、料金ページで Free が24時間、Hobbyist が72時間です。
ngrokのインストール(Windows・Mac・Linux)
この節では、OS ごとの入れ方と、入ったことの確かめ方が分かります。
アカウントを作る
ngrok のダッシュボード(dashboard.ngrok.com)でサインアップします。アカウントなしではエージェントのセッションを始められません(ERR_NGROK_4018)。
エージェントを入れる
下の表の OS ごとの方法で入れ、ngrok help でヘルプが出ることを確かめます。
authtoken を登録する
ダッシュボードの「Your Authtoken」にあるトークンを ngrok config add-authtoken で登録します。設定ファイル ngrok.yml に保存されます。
アプリを起動して公開する
手元でアプリを動かしてから ngrok http ポート番号 を実行し、表示された Forwarding の URL を開きます。
ngrok の公式クイックスタートとダウンロードページにある入れ方です。
| OS | 入れ方 | 補足 |
|---|---|---|
| Mac | brew install ngrok |
Homebrew を使う |
| Windows | Microsoft Store・winget install ngrok -s msstore・scoop install ngrok |
Store 版は自動で更新される。zip の単体の実行ファイルもある |
| Linux(Debian・Ubuntu) | 公式の apt リポジトリを登録して sudo apt install ngrok |
下のコマンド |
| その他 | ダウンロードページの tar・zip、Docker イメージ | FreeBSD・Raspberry Pi 向けもある |
Debian・Ubuntu で公式リポジトリから入れるコマンド(公式クイックスタートのまま)です。
curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \
| sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null \
&& echo "deb https://ngrok-agent.s3.amazonaws.com buster main" \
| sudo tee /etc/apt/sources.list.d/ngrok.list \
&& sudo apt update \
&& sudo apt install ngrok
入ったかどうかは、ヘルプか版の表示で確かめます。
ngrok help
ngrok version
公式ドキュメントの動作環境は、メモリ 64MB 以上(推奨 128MB)、ディスク 25MB、CPU の条件なしです。Windows は 64bit・32bit、Mac は Intel・Apple シリコン、Linux は x86-64・arm64 など多くの CPU に対応しています。
ダウンロードは公式サイトから行います。 公式 FAQ によると、ngrok は悪用されることがあるためウイルス対策ソフトに検出される場合があり、公式サイトから入れて、ngrok LLC または ngrok, Inc. の署名があるかを確かめるよう案内しています。
入れたあとは ngrok update で自分を更新できます。起動時に新しい版があると、Ctrl+U で更新するよう案内が出ます。2026年10月22日時点の最新版は、変更履歴で 3.39.12(2026年10月21日)です。
npm の ngrok パッケージと公式 SDK
npx ngrok http 8080 のように npm から使う記事もありますが、ngrok の公式ドキュメントが案内している JavaScript 用のパッケージは SDK の @ngrok/ngrok(npm install @ngrok/ngrok)、Python は pip install ngrok、Go は golang.ngrok.com/ngrok/v2 です。SDK は、アプリのコードの中からエンドポイントを作るためのライブラリです(例:Python の ngrok.forward(8080, ...))。
authtokenの設定と設定ファイル(ngrok.yml)の場所
この節では、authtoken の登録・確認と、トークンを漏らしたときの対処が分かります。
ngrok config add-authtoken $YOUR_TOKEN
$YOUR_TOKEN を、ダッシュボードの「Your Authtoken」のページに表示されたトークンに置き換えます。登録先は設定ファイル ngrok.yml です。公式ドキュメントにある、既定の場所は次のとおりです。
| OS | 設定ファイルの場所 |
|---|---|
| Linux | ~/.config/ngrok/ngrok.yml |
| Mac | ~/Library/Application Support/ngrok/ngrok.yml |
| Windows | %LocalAppData%\ngrok\ngrok.yml |
場所が分からないときは ngrok config check で確かめ、ngrok config edit で開いて編集できます。以前の版(v2)の記事にある ~/.ngrok2/ngrok.yml は v2 の形式で、公式ドキュメントでは v2 の形式は非推奨です。ngrok config upgrade で v3 の形式に書き換えられます。
登録した直後の ngrok.yml は、v3 の形式で次のような中身です(トークンは例)。
version: 3
agent:
authtoken: 4nq9771bPxe8ctg7LKr_2ClH7Y15Zqe4bWLWF9p
authtoken を GitHub などに公開してしまったら
authtoken はアカウントの鍵です。漏れると、他人があなたのアカウントでエンドポイントを作れます。
- ダッシュボードの authtoken のページでトークンを作り直します(リセット)。
- 手元で新しいトークンを
ngrok config add-authtokenで登録し直します。 - リセット前のトークンを使う設定が残っていると、
ERR_NGROK_107(The authtoken you specified is properly formed, but it is invalid.)で起動できなくなります。公式ドキュメントでも、原因の1つ目に「トークンをリセットした」が挙がっています。
鍵を誤って push したときの全体の手順は、関連記事「APIキーをGitHubにpushしてしまった時の対処手順」で扱っています。
ngrok http 8080 の使い方(基本のコマンド)
この節では、ポートの指定の仕方、HTTPS で動くアプリや別のPCの公開、オプションの書き方が分かります。
先に手元のアプリを起動し、そのポート番号を ngrok http に渡します。 公式クイックスタートの最小のアプリ(Python)は次の形です。
from http.server import BaseHTTPRequestHandler, HTTPServer
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(b"<h1>Hello from Python HTTP Server!</h1>")
HTTPServer(("", 8080), MyHandler).serve_forever()
ngrok http 8080
起動すると、ターミナルに状態の画面が出ます。公式ドキュメントの例では、公開 URL と転送先が次の1行で示されています。
Forwarding https://12345.ngrok.app -> http://localhost:8080
無料プランでは URL のドメインが ngrok-free.app などの dev domain になります(次の「固定URL」の節)。
上流(転送先)の書き方
| 書き方 | 意味 |
|---|---|
ngrok http 8080 |
http://localhost:8080 へ転送 |
ngrok http https://localhost:8443 |
手元のアプリが HTTPS で動いている |
ngrok http 192.168.1.2:80 |
同じ LAN の別の機器へ転送 |
ngrok tcp 22 |
HTTP 以外(SSH・DB など)を TCP で公開。無料はカード登録が要る |
手元のアプリが HTTPS で動いているのに ngrok http 8443 と書くと、ngrok は HTTP で話しかけてしまい、公式ドキュメントでは ERR_NGROK_3004(The server returned an invalid or incomplete HTTP response.)になるとされています。直し方は https://localhost:8443 のように URL の形で書くことです。
よく使うオプション(v3)
公式の CLI リファレンスでは、以前よく使われた --basic-auth・--oauth・--host-header・--region・--subdomain・--domain などは 非推奨(deprecated) になり、Traffic Policy か --url を使う形に変わっています。2026年10月22日時点で非推奨でない主なものです。
| オプション | 意味 |
|---|---|
--url |
エンドポイントの URL(独自のドメインは有料プラン) |
--traffic-policy-file |
Traffic Policy の YAML か JSON のファイル |
--pooling-enabled |
同じ URL を複数のエージェントで受ける |
--inspect |
localhost:4040 での記録の有無(既定は true) |
--upstream-tls-verify |
上流の HTTPS の証明書を検証する |
--name・--description |
エンドポイントの名前・説明 |
--authtoken |
このときだけ使う authtoken |
--config |
使う設定ファイル(複数なら合わせて読む) |
--region は非推奨で、公式の説明では ngrok がいちばん近い(遅延の少ない)地域を自動で選びます。
Webインスペクタ(localhost:4040)でリクエストを見る・再送する
この節では、届いたリクエストの見方、Replay、エージェントの API が分かります。
エージェントを動かしているPCのブラウザで http://localhost:4040 を開くと、届いた HTTP リクエストとレスポンスの一覧が見られます。 公式ドキュメントでは、時刻・かかった時間・送り元の IP・ヘッダー・クエリ・リクエストの本文・レスポンスの本文・通信の生のバイトまで表示されるとしています。
| 機能 | できること | 注意点 |
|---|---|---|
| 一覧と詳細 | Summary・Headers・Raw・Binary のタブで中身を見る | 本文が長いと先頭だけのことがある |
| JSON・XML の整形 | 自動で整形し、構文の誤りの位置を示す | ― |
| 絞り込み | パス・ステータス・サイズ・時間・ヘッダーの値で絞る | 複数の条件はすべてに合うものだけ |
| Replay | 同じリクエストを手元のアプリへ送り直す | Traffic Policy を通らずに直接届く |
| Replay with Modifications | メソッド・パス・ヘッダー・本文を変えて送る | ― |
/status |
設定と、接続数・応答時間の分布を見る | ― |
Replay は Webhook の開発で特に役立ちます。 送り手に同じイベントをもう一度起こしてもらわなくても、届いたリクエストをボタン1つで再現できます。ただし公式ドキュメントのとおり、Replay はエージェントから手元のアプリへ直接送るため、ngrok 側の認証や署名検証(Traffic Policy)は通りません。
インスペクタの場所は設定ファイルの web_addr(既定 127.0.0.1:4040)で変えられ、false で止められます。記録用のメモリは inspect_db_size(既定 50MB)です。
エージェントの API で公開 URL を取る
同じ 4040 番で、エージェントの状態を JSON で返す API も動いています。スクリプトから公開 URL を取り出すのに使えます。
curl http://localhost:4040/api/endpoints
公式ドキュメントの応答の例(要部)です。
{
"endpoints": [
{
"name": "command_line",
"uri": "/api/endpoints/command_line",
"url": "https://871e40f2d4c2.ngrok.paid.lan",
"upstream": {
"url": "http://localhost:8000",
"protocol": "https"
},
"inspect": true,
"pooling_enabled": true
}
]
}
以前の記事にある /api/tunnels は、公式ドキュメントで非推奨になり、/api/endpoints を使うよう案内されています。記録したリクエストは /api/requests/http で一覧でき、POST /api/requests/http に {"id": "..."} を送ると Replay と同じ再送ができます。
ngrokの固定URL(dev domain)と設定ファイルで複数を起動
この節では、URL が毎回変わるのか、複数のアプリをまとめて公開するにはどうするかが分かります。
2026年10月22日時点では、無料のアカウントにも「dev domain」という固定のドメインが1つ自動で割り当てられ、ngrok http を何度起動しても同じ URL になります。 公式ドキュメントでは「安定した、自動で割り当てられるホスト名」と説明され、例は your-assigned-name.ngrok-free.app です。ngrok のブログ(2023年4月6日)によると、無料ユーザーのドメインは ngrok-free.app と ngrok-free.dev です。
「URL が起動のたびに変わる」は以前の話
dev domain は自分では変えられない。好きな名前・自分のドメインは有料プラン
| ドメインの種類 | 例 | 使えるプラン |
|---|---|---|
| dev domain(自動で1つ) | 名前.ngrok-free.app |
すべて(無料はこれだけ) |
| ngrok のドメインで名前を選ぶ | my-app.ngrok.app など |
Hobbyist(10個まで)以上 |
| 自分のドメイン | app.example.com |
Pay-as-you-go 以上 |
| ワイルドカード | *.example.com |
Pay-as-you-go 以上 |
有料プランでは ngrok http 8080 --url https://my-app.ngrok.app のように URL を指定します。なお ngrok.io は、ドキュメントでは新規の提供を終え、以前からのアカウントだけが使えるドメインです。
ngrok.yml にエンドポイントを書いて起動する
毎回同じ設定で起動するなら、設定ファイルにエンドポイントを書きます。公式ドキュメントの v3 の形式です。
version: 3
agent:
authtoken: (登録したトークン)
endpoints:
- name: web
url: https://your-assigned-name.ngrok-free.app
upstream:
url: 8080
- name: api
upstream:
url: 3000
ngrok start web # 名前を指定して1つ起動
ngrok start --all # 書いたものをすべて起動
--all は、1つのエージェント(1つのセッション)で複数のエンドポイントを動かします。無料プランの「同時のエージェント3つまで」を超えて ngrok http を何個も起動すると ERR_NGROK_108 になり、公式ドキュメントはこの ngrok start --all を使うよう案内しています。
Webhookの受信テスト(ローカルのサーバーで受けた実物)
この節では、Webhook を手元で受けるサーバーの作り方と、署名の検証・重複の除外が実際にどう動くかが分かります。
流れは、公式ドキュメント「Test Webhooks Locally」のとおりです。
- 手元で Webhook を受けるサーバーを起動する(ここでは 29900 番)。
ngrok http 29900を実行する。- Forwarding の URL(例
https://your-name.ngrok-free.app/webhook)を、送り手(GitHub・Stripe など)の Webhook の設定に登録する。 - イベントを起こすと、手元のサーバーに届く。
ngrok は、手元へ渡すリクエストに次のヘッダーを付けます(公式ドキュメントの HTTP エンドポイントの説明)。
| ヘッダー | 中身 |
|---|---|
X-Forwarded-For |
送り元(クライアント)の IP。元からあれば後ろに足す |
X-Forwarded-Proto |
元の通信が http か https か。元からあれば後ろに足す |
X-Forwarded-Host |
送り元が付けた値。無ければ元の Host ヘッダーの値 |
値は後ろに足されるので、ドキュメントは X-Forwarded-For と X-Forwarded-Proto は最後の値を読む よう案内しています。
受けるサーバー(Python・標準ライブラリだけ)
GitHub の Webhook を受ける例です。GitHub の公式ドキュメントのとおり、X-Hub-Signature-256 ヘッダーの sha256= に続く値(シークレットと本文から作った HMAC-SHA256 の16進)を、固定時間で比べる関数(hmac.compare_digest)で照合します。
# receiver.py Webhook を受けるローカルのサーバー(ポート 29900)
import hmac, hashlib, json, os
from http.server import BaseHTTPRequestHandler, HTTPServer
SECRET = os.environ.get("WEBHOOK_SECRET", "").encode()
seen = set() # 処理済みの配信ID(本番では DB に保存する)
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
print(f"--- {self.command} {self.path}")
for k in ("Host", "Content-Type", "X-GitHub-Event", "X-GitHub-Delivery",
"X-Hub-Signature-256", "X-Forwarded-For", "X-Forwarded-Proto", "X-Forwarded-Host"):
if k in self.headers:
print(f"{k}: {self.headers[k]}")
print("body:", body.decode()[:200])
# 署名を確かめる(GitHub 形式:sha256=HMAC-SHA256(secret, 本文) の16進)
expected = "sha256=" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()
got = self.headers.get("X-Hub-Signature-256", "")
if not hmac.compare_digest(expected, got):
print("signature: NG -> 401")
self.send_response(401); self.end_headers(); self.wfile.write(b"invalid signature\n")
return
# 送信元の IP は X-Forwarded-For の最後の値を使う
xff = self.headers.get("X-Forwarded-For")
client = xff.split(",")[-1].strip() if xff else self.client_address[0]
print("signature: OK client:", client)
delivery = self.headers.get("X-GitHub-Delivery")
if delivery in seen: # Replay・再送で同じ配信が2回来た
print("duplicate:", delivery, "-> skip")
self.send_response(200); self.end_headers(); self.wfile.write(b"duplicate\n")
return
seen.add(delivery)
self.send_response(200); self.send_header("Content-Type", "application/json"); self.end_headers()
self.wfile.write(json.dumps({"ok": True}).encode() + b"\n")
def log_message(self, fmt, *args):
print("access:", fmt % args)
HTTPServer(("127.0.0.1", 29900), Handler).serve_forever()
WEBHOOK_SECRET=s299-test-secret python3 -u receiver.py
結果1:正しい署名のリクエストは 200
GitHub の pull_request イベントと同じ形のリクエスト(署名・配信 ID・ngrok が付けるのと同じ名前の X-Forwarded 系ヘッダー付き)を、自作の送信スクリプト(send.py。Python の urllib で送る)で送りました。サーバーに出たログです。
--- POST /webhook
Host: your-name.ngrok-free.app
Content-Type: application/json
X-GitHub-Event: pull_request
X-GitHub-Delivery: 39781146-a1eb-47ac-8bc7-b82334681d7b
X-Hub-Signature-256: sha256=52dc97f9b9fafe8e56de74e43e70ff47d2684f06018b138beee3866e7e518cb9
X-Forwarded-For: 203.0.113.10
X-Forwarded-Proto: https
X-Forwarded-Host: your-name.ngrok-free.app
body: {"action": "opened", "number": 42, "repository": {"full_name": "example/app"}}
signature: OK client: 203.0.113.10
access: "POST /webhook HTTP/1.1" 200 -
送った側には 200 {"ok": true} が返りました。Host が公開 URL のドメインになっている点に注目します。これが次の節の「ホストが許可されていない」エラーの原因です。
結果2:本文を書き換えると署名が合わず 401
署名を作ったあとで本文の "number": 42 を 43 に書き換えて送ると、署名が合わず 401 になりました。
body: {"action": "opened", "number": 43, "repository": {"full_name": "example/app"}}
signature: NG -> 401
access: "POST /webhook HTTP/1.1" 401 -
ngrok の URL は誰でも開けるので、Webhook の受け口は署名で送り手を確かめます。 ngrok 側で確かめる方法もあります。Traffic Policy の verify-webhook を使うと、署名の合わないリクエストは ngrok が 403 で止め、手元のアプリまで届きません(GitHub・Stripe・Shopify・Slack・Twilio など多数に対応。無料プランは月500回まで)。
# policy.yml(公式ドキュメントの例を GitHub 用に変えたもの)
on_http_request:
- actions:
- type: verify-webhook
config:
provider: github
secret: (GitHub に設定したシークレット)
ngrok http 29900 --traffic-policy-file policy.yml
結果3:同じ配信 ID が2回来たら処理しない
インスペクタの Replay や、送り手の再送(Redeliver)を使うと、同じリクエストがもう一度届きます。GitHub の公式ドキュメントでは、再送しても X-GitHub-Delivery は元の配信と同じ値です。同じ配信 ID で2回送った結果です。
$ python3 send.py ok 7f0c1a2e-0000-4000-8000-000000000001
200 {"ok": true}
$ python3 send.py ok 7f0c1a2e-0000-4000-8000-000000000001
200 duplicate
signature: OK client: 203.0.113.10
duplicate: 7f0c1a2e-0000-4000-8000-000000000001 -> skip
access: "POST /webhook HTTP/1.1" 200 -
2回目も 200 を返しているのは、送り手に「受け取った」と伝えて再送を止めるためです。GitHub の公式ドキュメントでは、受けたサーバーは 10秒以内に 2XX を返す必要があり、時間のかかる処理はキューに入れて後で行うよう勧めています。
| 確かめること | 手元での確かめ方 | ngrok での確かめ方 |
|---|---|---|
| 送り手が本物か | 署名ヘッダーを HMAC で照合 | Traffic Policy の verify-webhook |
| 同じ配信の重複 | 配信 ID を保存して2回目は処理しない | インスペクタの Replay で再現して試す |
| 応答の速さ | 受けたらすぐ 2XX、処理は後で | インスペクタで応答時間を見る |
| 送り元の IP | X-Forwarded-For の最後の値 |
インスペクタの送り元 IP |
署名・リトライ・冪等性(何度受けても結果が同じになる設計)の詳しい作り方は、関連記事「Webhookとは?実装までわかる|署名検証・リトライ・冪等性を実行ログで解説」で扱っています。
「Blocked request」「Invalid HTTP_HOST header」の直し方(Vite・Django)
この節では、ngrok の URL を開くと開発サーバーが拒否する理由と、その直し方が分かります。
ngrok は元の Host ヘッダー(your-name.ngrok-free.app)のまま手元のアプリへ渡します。開発サーバーの多くは、知らないホスト名のリクエストを断る仕組み(DNS リバインディング対策)を持っています。そのため ngrok 自体は動いているのに、アプリが 403 や 400 を返す ことがあります。
Vite:Blocked request. This host is not allowed.
Vite 8.3.5 の開発サーバー(29910 番)に、ngrok と同じ Host ヘッダーで curl を送りました。
$ curl -i http://localhost:29910/ -H 'Host: your-name.ngrok-free.app'
HTTP/1.1 403 Forbidden
Vary: Origin
Content-Type: text/plain
Blocked request. This host ("your-name.ngrok-free.app") is not allowed.
To allow this host, add "your-name.ngrok-free.app" to `server.allowedHosts` in vite.config.js.
vite.config.js に server.allowedHosts を書いて起動し直すと、200 になりました。
import { defineConfig } from 'vite'
export default defineConfig({
server: {
// 先頭の . で、ngrok-free.app のすべてのサブドメインを許可
allowedHosts: ['.ngrok-free.app'],
},
})
$ curl -s -o /dev/null -w '%{http_code}\n' http://localhost:29910/ -H 'Host: your-name.ngrok-free.app'
200
$ curl -s -w '\n%{http_code}\n' http://localhost:29910/ -H 'Host: evil.example.com'
Blocked request. This host ("evil.example.com") is not allowed.
To allow this host, add "evil.example.com" to `server.allowedHosts` in vite.config.js.
403
Vite の allowedHosts の書き方
allowedHosts: true(どのホストも許可)allowedHosts: ['.ngrok-free.app']Vite の公式ドキュメントは true を DNS リバインディング攻撃を受けうる設定とし、許可するホストを明示する書き方を勧めている
Vite の設定のほかの項目は、関連記事「vite.configの書き方|用途別コピペ一覧とVite 8の変更点」で扱っています。
Django:Invalid HTTP_HOST header と CSRF の Origin checking failed
Django 5.2.18 の開発サーバー(29920 番、DEBUG = True・ALLOWED_HOSTS = [] のまま)に同じように送ると、400 になり、サーバーのログに次の1行が出ました。
Invalid HTTP_HOST header: 'your-name.ngrok-free.app'. You may need to add 'your-name.ngrok-free.app' to ALLOWED_HOSTS.
settings.py の ALLOWED_HOSTS に足すと、画面は開けるようになりました。ところが、管理画面のログインのように POST するフォームは、続けて 403 になりました。
Forbidden (Origin checking failed - https://your-name.ngrok-free.app does not match any trusted origins.): /admin/login/
ブラウザは Origin: https://your-name.ngrok-free.app を付けて送りますが、Django から見ると自分は http で動いているため、出どころが一致しないと判断されます。CSRF_TRUSTED_ORIGINS に足すと、CSRF の確認を通り、ログイン画面の通常の応答(ユーザー名かパスワードが違う、という 200 の画面)に変わりました。
# settings.py(開発用)
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '.ngrok-free.app']
CSRF_TRUSTED_ORIGINS = ['https://*.ngrok-free.app']
| フレームワーク | 症状(原文) | 直す設定 |
|---|---|---|
| Vite | Blocked request. This host (...) is not allowed.(403) |
server.allowedHosts |
| Django | Invalid HTTP_HOST header: ...(400) |
ALLOWED_HOSTS |
| Django(POST) | Origin checking failed - ... does not match any trusted origins.(403) |
CSRF_TRUSTED_ORIGINS(https:// から書く) |
Django の公式ドキュメントでは、ALLOWED_HOSTS の先頭の . はサブドメインのワイルドカード、CSRF_TRUSTED_ORIGINS は https://*.example.com の形でサブドメインを許可できます。これらは開発用の設定として、公開する環境の設定とは分けて置くのが目安です。
アプリに別の Host ヘッダーを渡したいとき
アプリが特定のホスト名(例:localhost)でしか動かない場合は、ngrok 側で Host を書き換えられます。以前の --host-header=rewrite は非推奨で、Traffic Policy の add-headers を使います。公式ドキュメントでは、host を指定したときだけは値を足さずに置き換え、レスポンスの location ヘッダーも公開 URL に合わせて書き換えるとしています。
on_http_request:
- actions:
- type: add-headers
config:
headers:
host: localhost
ngrokの注意点(危険性・公開してよいもの・認証のかけ方)
この節では、ngrok で公開するときに何に気をつけ、どう守るかが分かります。
ngrok の URL は、知っている人なら誰でも開けます。 手元の開発サーバーは、本番より守りが弱いことが多い(デバッグ画面・管理画面・テスト用のデータ)ため、公開する前に何を見せるかを決めます。
公開してよいもの
Webhook の受け口(署名で送り手を確かめる)
見せる相手と時間を決めた試作の画面
ダミーのデータだけを持つ開発用の API
公開しないもの
本物の顧客データ・社内の情報が見える画面
認証の無い管理画面・DB の管理ツール
会社の規則で外部への公開が禁じられているもの
認証をかける(Basic 認証・OAuth・IP 制限)
認証は Traffic Policy で、ngrok の側でかけます。手元のアプリまで届く前に止まるので、アプリを変えなくて済みます。
Basic 認証(公式ドキュメントの basic-auth。パスワードは8〜128文字、10組まで):
# policy.yml
on_http_request:
- actions:
- type: basic-auth
config:
credentials:
- "alice:correct-horse-battery"
Google アカウントでのログイン(oauth。会社のドメイン以外を断る例。公式クイックスタートより):
on_http_request:
- actions:
- type: oauth
config:
provider: google
- expressions:
- "!actions.ngrok.oauth.identity.email.endsWith('@example.com')"
actions:
- type: deny
IP アドレスで絞る(restrict-ips):
on_http_request:
- actions:
- type: restrict-ips
config:
enforce: true
allow:
- "203.0.113.0/24"
ngrok http 8080 --traffic-policy-file policy.yml
公式ドキュメントでは、用意された Google の OAuth アプリはテスト・開発用で、本番では自分の OAuth アプリを使うよう案内しています。また無料プランでは、1つの Policy に書ける規則は5つまでです。
公開する前のチェックリスト
ngrokのエラー一覧と直し方(ERR_NGROK_8012など)
この節では、よく出るエラーの原文と、原因・直し方が分かります。
ngrok のエラーには ERR_NGROK_番号 が付きます。公式のエラーリファレンスの原文です。
| エラー | 原文(要部) | 原因と直し方 |
|---|---|---|
| ERR_NGROK_4018 | This ngrok session is not authenticated. | authtoken が未登録。サインアップして ngrok config add-authtoken |
| ERR_NGROK_105 | The authtoken you specified does not look like a proper ngrok authtoken. | トークンの貼り間違い。ダッシュボードからもう一度コピー |
| ERR_NGROK_107 | ... is properly formed, but it is invalid. | トークンをリセットした・チームから外れた。新しいトークンを登録 |
| ERR_NGROK_8012 | ... the agent failed to establish a connection to the upstream web service | 手元のアプリが起動していない・ポート番号が違う |
| ERR_NGROK_3200 | The endpoint is offline. | エージェントが止まっている・URL の打ち間違い |
| ERR_NGROK_3004 | The server returned an invalid or incomplete HTTP response. | HTTPS のアプリに HTTP で転送。https://localhost:ポート と書く |
| ERR_NGROK_108 | Your account is limited to MAX simultaneous ngrok agent sessions. | エージェントの起動しすぎ。ngrok start --all にまとめる |
| ERR_NGROK_334 | The endpoint URL is already online. | 同じ URL を別の場所で起動中。止めるか --pooling-enabled |
| ERR_NGROK_725 | ... has reached its network bandwidth limit for the month. | 月のデータ転送の上限。翌月を待つか有料プラン |
| ERR_NGROK_121 | Your ... version ... is too old. | エージェントの版が対応の下限より前。ngrok update |
| ERR_NGROK_6024 | You are about to visit ... | 無料プランの警告ページ。下の説明 |
ERR_NGROK_8012 は、まず手元で curl する
8012 は「ngrok までは届いたが、手元のアプリにつながらない」というエラーです。ngrok を通さずに、手元で同じポートへ curl すると原因が分かります。アプリが動いていないポート(29901 番)へ送った結果です。
$ curl -i http://127.0.0.1:29901/
curl: (7) Failed to connect to 127.0.0.1 port 29901 after 0 ms: Couldn't connect to server
手元の curl がつながらないなら、原因は ngrok ではなくアプリの側です(起動していない・別のポートで動いている・起動に失敗した)。どのポートで何が動いているかの調べ方は、関連記事「ポートを使っているプロセスの調べ方|ss・lsof・netstat比較」で扱っています。接続拒否の原因の切り分けは、関連記事「localhostで接続が拒否されましたの原因と解決方法」で扱っています。
ERR_NGROK_6024(警告ページ)を API の呼び出しで出さない
無料プランでは、ブラウザで開くと「You are about to visit ...」という警告ページが出ます。プログラムからの呼び出しには出ませんが、ブラウザの JavaScript(fetch)から ngrok の API を呼ぶと、この HTML が返ってきて JSON として読めないことがあります。公式ドキュメントの回避方法は次の2つです。
- リクエストに
ngrok-skip-browser-warningヘッダーを付ける(値は何でもよい)。 - 一般的なブラウザでない User-Agent を付ける。
curl -H "ngrok-skip-browser-warning: 1" https://your-name.ngrok-free.app/api/items
fetch(url, { headers: { 'ngrok-skip-browser-warning': '1' } })
有料プランでは警告ページは出ません。
ngrokの代替(Cloudflare Tunnel・localhost.run・Tailscale Funnel など)との違い
この節では、似たことができるサービスとの違いと、選び方が分かります。
各サービスの公式ドキュメントで確かめた事実を並べます(2026年10月22日時点)。
| サービス | 始め方 | アカウント | 公開 URL | 公式ドキュメントにある特徴 |
|---|---|---|---|---|
| ngrok | ngrok http 8080 |
要る | 名前.ngrok-free.app(無料は固定1つ) |
インスペクタと Replay、Traffic Policy |
| Cloudflare Tunnel(Quick Tunnel) | cloudflared tunnel --url http://localhost:8080 |
無くても試せる | ランダム.trycloudflare.com |
テスト・開発専用。同時200リクエストまで、SSE 非対応 |
| localhost.run | ssh -R 80:localhost:8080 localhost.run |
無料のドメインは不要 | localhost.run が割り当てる | ssh だけで使え、何も入れなくてよい |
| Tailscale Funnel | tailscale funnel 3000 |
要る(tailnet) | マシン名.tailnet名.ts.net |
ポートは 443・8443・10000。MagicDNS と HTTPS の有効化が要る |
| VS Code のポート転送 | Ports ビューで Forward a Port | GitHub か Microsoft | VS Code が発行する URL | 既定は Private(同じアカウントのサインインが要る) |
flowchart TD
Q[誰に見せるか] -->|インターネットの誰でも| W{中身を見て<br>再送したい}
Q -->|自分と仲間だけ| T[Tailscale や<br>VS Code の Private]
W -->|はい| N[ngrok]
W -->|いいえ・登録なしで| C[Cloudflare Quick Tunnel<br>や localhost.run]
| 状況 | 合う選択肢 | 理由 |
|---|---|---|
| Webhook を受けて、中身を見ながら直したい | ngrok | インスペクタと Replay がある。URL が固定 |
| 登録せずに、今すぐ1回だけ見せたい | Cloudflare Quick Tunnel・localhost.run | アカウントなしで試せる |
| チームの中だけで見せたい | Tailscale(Funnel を使わない)・VS Code の Private | インターネットに公開しない |
| ずっと公開し続けたい | 本番用のホスティング・各社の有料の仕組み | 開発用のトンネルは一時的な公開向け |
Tailscale の仕組みと Funnel・Serve の違いは、関連記事「Tailscaleとは|使い方・料金・VPNとの違いをWireGuardで実演」で扱っています。
よくある質問
Q. ngrok の読み方は? A. 公式 FAQ では「en-grok」で、日本語では「エングロック」と読まれます。
Q. ngrok は無料で使えますか? A. 使えます。2026年10月22日時点の無料プランは、月にデータ転送1GB・HTTP リクエスト2万回・同時のエンドポイント3つまでで、dev domain が1つ付きます。「ngrokの料金と無料プランの制限」の節に表があります。
Q. ngrok の無料版に時間制限はありますか? A. 公式ドキュメントでは、無料のエンドポイントにタイムアウトは無く、いつまでもオンラインにできるとされています。上限は時間ではなく、月の転送量・リクエスト数です。
Q. ngrok の URL を固定するには?
A. 無料でも自動で割り当てられる dev domain(名前.ngrok-free.app)が固定で使えます。好きな名前や自分のドメインにするのは有料プランで、--url で指定します。
Q. ngrok は危険ですか? A. ngrok 自体は正規のサービスですが、公開した URL は誰でも開けます。認証の無い管理画面や本物のデータを公開しない、Basic 認証・OAuth・IP 制限か Webhook の署名検証をかける、使い終わったら止める、の3つが目安です。ダウンロードは公式サイトから行います。
Q. ngrok で Basic 認証をかけるには?
A. 以前の --basic-auth は非推奨になり、Traffic Policy の basic-auth を YAML に書いて --traffic-policy-file で渡します。パスワードは8〜128文字です。
Q. ERR_NGROK_8012 が出ます。
A. ngrok までは届いているが、手元のアプリにつながっていません。アプリが起動しているか、ngrok http に渡したポート番号がアプリと同じかを、手元の curl で確かめます。
Q. ngrok の URL を開くと「Blocked request」や「Invalid HTTP_HOST header」になります。
A. ngrok ではなくアプリ側の拒否です。Vite は server.allowedHosts、Django は ALLOWED_HOSTS(POST するなら CSRF_TRUSTED_ORIGINS も)に ngrok-free.app を足します。
Q. LINE Bot や Stripe の Webhook を手元で試せますか?
A. 試せます。ngrok http ポート番号 で出た URL を、各サービスの Webhook の設定に登録します。署名の確かめ方は送り手ごとに決まっているので、各サービスのドキュメントに従います。
Q. ngrok の代わりになるものは? A. Cloudflare Tunnel(Quick Tunnel)、localhost.run、Tailscale Funnel、VS Code のポート転送などがあります。違いは「代替との違い」の節の表にまとめています。
まとめ
- ngrok は、手元のアプリに HTTPS の公開 URL を付けるサービス。エージェントが外向きの TLS(443)でつなぐので、ポート開放は要らない。
- 始め方は、アカウント作成 → インストール →
ngrok config add-authtoken→ngrok http ポート番号。 - 2026年10月22日時点の無料プランは、月1GB・2万リクエスト・エンドポイント3つ。dev domain が固定で1つ付き、時間制限は無い。
localhost:4040で届いたリクエストを見て、Replay で送り直せる。Replay は ngrok 側の認証・検証を通らない。- Webhook の受け口は、署名を
hmac.compare_digestで照合し、配信 ID で重複を除き、すぐに 2XX を返す。実験では改ざんで 401、同じ配信 ID の2回目は処理されなかった。 - Vite・Django はホスト名で拒否する。
allowedHosts・ALLOWED_HOSTS・CSRF_TRUSTED_ORIGINSにngrok-free.appを足すと直った。 --basic-authなどは非推奨。認証は Traffic Policy のbasic-auth・oauth・restrict-ipsでかける。
参考・出典
確認日はいずれも 2026年10月22日です。
- ngrok「Share Localhost Quickstart」:https://ngrok.com/docs/share-localhost/quickstart
- ngrok「How Sharing Localhost Works」:https://ngrok.com/docs/share-localhost/tunnels
- ngrok「How ngrok Agents Work」:https://ngrok.com/docs/gateway/agent/how-it-works
- ngrok「Install the ngrok Agent CLI」:https://ngrok.com/docs/gateway/agent/install
- ngrok「ngrok Agent Changelog」:https://ngrok.com/docs/gateway/agent/changelog
- ngrok「Agent Command Line Interface」:https://ngrok.com/docs/gateway/agent/cli
- ngrok「Agent Configuration File」:https://ngrok.com/docs/agent/config
- ngrok「Agent Configuration File v3」:https://ngrok.com/docs/gateway/agent/config/v3
- ngrok「Web Inspection Interface」:https://ngrok.com/docs/gateway/agent/web-inspection-interface
- ngrok「Agent API」:https://ngrok.com/docs/gateway/agent/api
- ngrok「Test Webhooks Locally」:https://ngrok.com/docs/share-localhost/webhooks
- ngrok「Authentication」:https://ngrok.com/docs/share-localhost/auth
- ngrok「Network Security」:https://ngrok.com/docs/share-localhost/security
- ngrok「Basic Auth action」:https://ngrok.com/docs/traffic-policy/actions/basic-auth
- ngrok「HTTP Cloud Endpoints」(ヘッダー):https://ngrok.com/docs/gateway/endpoints/cloud-endpoints/http
- ngrok「Domains」:https://ngrok.com/docs/domains
- ngrok「Free Plan Limits」:https://ngrok.com/docs/pricing-limits/free-plan-limits
- ngrok「Pricing and Limits」:https://ngrok.com/docs/pricing-limits
- ngrok「Pricing」:https://ngrok.com/pricing
- ngrok「Download ngrok(Windows)」:https://ngrok.com/download/windows
- ngrok「FAQ」:https://ngrok.com/docs/faq
- ngrok「Errors Reference」:https://ngrok.com/docs/errors/reference
- ngrok ブログ「New ngrok domains」:https://ngrok.com/blog-post/new-ngrok-domains
- ngrok/ngrok-docs(公式ドキュメントの原稿):https://github.com/ngrok/ngrok-docs
- GitHub Docs「Webhook を使用するためのベスト プラクティス」:https://docs.github.com/ja/webhooks/using-webhooks/best-practices-for-using-webhooks
- GitHub Docs「Webhook 配信を検証する」:https://docs.github.com/ja/webhooks/using-webhooks/validating-webhook-deliveries
- Vite「Server Options」(server.allowedHosts):https://vite.dev/config/server-options
- Django「Settings」(ALLOWED_HOSTS・CSRF_TRUSTED_ORIGINS):https://docs.djangoproject.com/en/5.2/ref/settings/
- Cloudflare「Quick Tunnels」:https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/
- localhost.run「Documentation」:https://localhost.run/docs/
- Tailscale「Tailscale Funnel」:https://tailscale.com/kb/1223/funnel
- Visual Studio Code「Port forwarding」:https://code.visualstudio.com/docs/debugtest/port-forwarding
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「ngrokとは|使い方・料金・Webhook受信とエラーの直し方」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。