どの Webhook プロバイダーと連携するときも、作業を始めて 30 秒で手に取るのが ngrok です。ngrok http 3000 を起動し、公開 URL を Stripe のダッシュボードに貼り付ければ、1 分もしないうちにローカルのハンドラーのブレークポイントで止まります。開発サイクルの速さでは、明らかに勝ちです。
問題は、ngrok が本来想定されていない場面でも使われ続けることです:ステージング環境、「一時的な」本番用のトンネル、本番障害のデバッグ。チームが何時間も無駄にするのはそこです。この記事では、ngrok の役目がどこで終わり、その先で実際に何が必要になるのかを説明します。
TL;DR
- ngrok はローカル開発に適したツールで、そこでは ngrok に勝るものはありません。使い続けてください。
- ノート PC を閉じても生き残る必要があるものには向きません:ステージング、本番、長時間のデバッグ、監査、障害からの復旧
- ローカル開発の先で必要なのは、永続化、再送、ファンアウト(1 つのイベントを複数の転送先に配信)です。それを提供するのが Webhook 中継サービスです
- うまくいくパターンは、ngrok と中継サービスの両方を使うことで、どちらか一方ではありません
ngrok が得意なこと
1 つは、署名シークレットのローカルでのテストです。署名検証を実際に動かすには、署名付きのリクエストを本当に受け取るしかなく、ngrok ならそれができます。
もう 1 つは、失敗時の経路のテストです。ハンドラーから 500 を返し、Stripe のダッシュボードで配信が失敗と表示されるのを確認し、リトライのロジックを検証します。
プロバイダーが送る正確なヘッダーを、変わったものも含めて見るにも、いちばん速い方法です。使い捨てのデモで、チームメイトに連携が動くところを見せたいなら、20 分だけ ngrok で公開して、次に進めます。
こうした用途には完璧です。使い続けてください。
ngrok では足りなくなるところ
ステージング環境です。誰かのノート PC 上のトンネルにステージングを依存させたくはありませんし、トンネルはノート PC がスリープすると止まります。ステージングは「最後に Webhook を設定した人」次第になり、エンジニア 1 人の稼働状況にみんなが依存することになります。
本番環境です。言うまでもありません。
長時間のデバッグです。1 日に 1 回しか起きないバグを再現するのに 3 日分の Webhook の記録が必要でも、ngrok の無料プランが保持するのは 24 時間分のトラフィックだけです。有料プランなら足りますが、それではトンネルにロギングの料金を払うことになり、形が間違っています。
サポートや開発者以外のチームメイトへの引き継ぎです。必要なのは、「先に ngrok を起動するから」がなくても動く URL です。
監査への対応です。コンプライアンスのチームから「第 1 四半期に受信したすべての Webhook イベントを見せてほしい」と言われても、ngrok には何も残っていません。
障害からの復旧です。サーバーがダウンしていて、Stripe のリトライ期間が過ぎてしまったら、ngrok にはそのイベントがありません。
トンネルの先で必要なもの
「とりあえず localhost に POST できればいい」の段階を過ぎると、問題の実際の形は次のようになります:
- どのノート PC にも依存しない、安定した公開 URL
- 永続化。受信したすべてのイベントが保存され、後から読めること
- 複数の宛先への配信:開発用の localhost、チームメイト用のステージング、実トラフィック用の本番環境に、1 つの受信 URL から配信すること
- 再送。「昨日のあのイベントを、もう一度ハンドラーに送って」ということ
- リトライとアラート。不安定なエンドポイントにはリトライがかかり、そのことが通知されること
これは別の種類のツールです。人によって、Webhook 中継サービスと呼んだり、Webhook プロキシと呼んだりします。
Webhook 中継サービスの役割
中継サービスは、プロバイダーとエンドポイントの間に入ります。プロバイダーは 1 つの安定した URL(in.anyhook.net/you/stripe)に送り、配信、リトライ、ロギング、再送は中継サービスが担います。
ローカル開発では、トンネルの URL を本番と並べて転送先に追加すれば、受信したイベントはすべて両方に配信されます。ノート PC にライブでイベントが届くという ngrok の体験はそのままに、トンネルの劣化に悩まされることはありません。ノート PC がスリープしても、失敗するのはトンネルの転送先だけです。本番は動き続け、イベントは記録され続け、ノート PC への失敗した配信は、戻ってきたらいつでも再送できるよう残っています。
ステージング環境は、もう 1 つの転送先として追加します。Pro 以上なら、イベントタイプフィルターで本番トラフィックの一部だけをそこに送れます。デバッグでは、イベントログをステータスや App(Webhook の送信元ごとに作る受信設定)で絞り込み、再現したいものを再送します。
ngrok + AnyHook という実用的な組み合わせ
困っているのが、再起動のたびにトンネルの URL が変わり、プロバイダーのダッシュボードに貼り直し続けていることなら、それには短い答えがあります:プロバイダーには変わらない URL を渡してください。
実際にうまくいく組み合わせはこうです:新しい連携の最初の 30 分は ngrok を使います。「自分のマシンでは動く」にたどり着くいちばん速い方法だからです。そこから先はすべて AnyHook を使います。つまり、永続的なロギング、複数の環境へのファンアウト、再送、リトライ、アラートです。
AnyHook は、誰のノート PC にも依存しない安定した受信 URL を提供し、複数の転送先(本番、ステージング、自分のトンネルなど、どこでも)に転送し、再送できる完全なログを残します。ローカル開発では ngrok を使い続けます。そこでは ngrok に勝るものがないからです。そして、失ったら困るものに ngrok を使うのはやめます。
「とりあえず ngrok で」のコスト
Webhook の問題にいちばん時間を取られるのは、ほぼ例外なく、ngrok を本番の戦略として扱ったチームです:
- 誰かがノート PC を閉じるたびに、ステージングが壊れます
- 本番障害のたびに、取り返しのつかないデータの欠落が残ります
- 「あのイベントのペイロードは何だった?」に、2 日後には答えられません
- 再送の元になるイベント履歴がないので、新しく入ったエンジニアがバグを再現できません
ngrok にお金を払っても、どれも解決しません。同じノート PC へのより速いトンネルも、ノート PC へのトンネルであることに変わりはありません。
まとめ
ローカル開発の先で必要なのは、開発者のマシン以外の場所にある Webhook の層です:永続的で、再送でき、いくつもの転送先にファンアウトできるものです。それが、Webhook を毎週の火消しから解放する転換です。
そもそもプッシュを受け取るかどうかを迷っているなら、「Webhook とポーリングの違い」が、効率ではなく壊れ方で選ぶ議論をしています。サーバーレスですでに受信しているなら、ローカルでは決して壊れず本番でだけ壊れる部分は、「Vercel で Webhook を取りこぼさずに受信する」で扱っています。