Development
15 min read
58 views

CI/CD向けプログラム的トンネル:Webhookテストのための一時URL自動化

IT
InstaTunnel Team
Published by the InstaTunnel team | Editorial policy
CI/CD向けプログラム的トンネル:Webhookテストのための一時URL自動化

Quick answer

Programmatic Tunnels for CI/CD: Automated Webhook & Endpoint: quick comparison answer

Choose the tunnel tool based on the network model: public HTTPS URLs for webhooks and demos, private mesh access for internal apps, and managed infrastructure when policy controls matter most.

Which tunnel tool is best for public webhook testing?

Use a public HTTPS localhost tunnel with stable URLs. InstaTunnel focuses on webhook testing, demos, OAuth callbacks, and MCP endpoint workflows.

When should I choose a private network tool instead?

Choose a private mesh or Zero Trust tool when every user and service should stay inside a controlled private network.

長年、ローカルトンネルは個々の開発者がノートパソコン上でCLIバイナリを実行する範囲に限定されていました。Stripeの支払いをテストしたり、GitHubイベントを検証したりする必要がある場合、ターミナルを開き、コマンドを実行し、URLをコピーしてダッシュボードに手動で貼り付けていました。2026年現在もこのワークフローは存在しますが、高度なQAやプラットフォームチームはますますこれを省略しています。代わりに、CLIバイナリを手動で実行するのではなく、テストスイートやCI/CDジョブから直接、一時的な公開URLを*プログラム的に*生成します。Node.jsコードにトンネルライブラリを直接インポートすることで、エンジニアリングチームは完全に自動化されたエンドポイントテストと真のエンドツーエンドWebhook検証を実現し、人間がターミナルに触れることはありません。

CLIからコードへの移行

コマンドラインのトンネリングツールはローカル開発には最適です。ngrok、Pinggy、Cloudflare Tunnelなどのツールは、1つのコマンドでlocalhostのポートを共有する開発者体験を完成させています。しかし、CLIは自動化に移行するときに摩擦を生みます。CI/CDパイプラインがアプリケーションが受信するWebhookを正しく処理しているか検証する必要がある場合、スタンドアロンのバイナリは扱いにくいです。デタッチされたバックグラウンドプロセスとして起動し、標準出力から動的に生成されたURLを抽出し、そのライフサイクルを慎重に管理し、ランナーに孤立したプロセスが残らないようにする必要があります。

プログラム的なトンネルはこれをすっきりと解決します。外部バイナリにシェルでアクセスする代わりに、ライブラリをテストスイートやアプリケーションコードに直接インポートします。トンネルは単なる非同期関数呼び出しとなり、公開URLを解決し、ヘッドレスブラウザやサードパーティAPIに渡す準備が整います。

npmのlocaltunnelの遺産と開発者の代替先

歴史的に、Node.js開発者はこれを解決するためにlocaltunnel npmパッケージを使用してきました。これは非常に便利で、JavaScriptの数行でポートを公開できました:

const localtunnel = require('localtunnel');

(async () => {
  const tunnel = await localtunnel({ port: 3000 });

  // 例: https://abcdefgjhij.loca.lt
  console.log(tunnel.url);

  tunnel.on('close', () => {
    // トンネルが閉じられた
  });
})();

このプロジェクトはまだnpmにあり動作していますが、そのGitHubの履歴は独自の物語を語っています。元のリポジトリは長期間メンテナンス活動が少なく、コミュニティはそれに応じて12以上の独立したフォークやラッパーパッケージ(tunnelout、Docker化されたlocaltunnel-serverイメージ、言語ポートなど)を作成し、エコシステムを維持してきました。このパターンは、多くのフォークと不一致のアップストリーム対応を示しており、チームが無料のloca.ltサービスにCIインフラを依存すべきではないサインです。2026年までに、多くのチームはより新しく、積極的にメンテナンスされている代替ツールに移行しています。

以下は、それらのツールと修正済みの検証済みコードの一覧です:

Tunnelmole

Tunnelmoleは完全にオープンソースのトンネリングツールです。クライアントはMITライセンス、バックエンドサービスはAGPLv3ライセンスで、どちらも監査やセルフホストが可能です。Node.jsエコシステム向けにネイティブにTypeScriptで書かれており、外部バイナリをラップしていません。

実際のプログラム的API(以前のserve()関数の誤った記述を修正)は、単一の関数で、ESモジュールとCommonJSの両方としてエクスポートされています:

// ESM
import { tunnelmole } from 'tunnelmole';

// CommonJS
// const tunnelmole = require('tunnelmole/cjs');

const url = await tunnelmole({ port: 3000 });
// url = https://idsq6j-ip-157-211-195-169.tunnelmole.net

この関数はasyncで、割り当てられた公開URLを直接返します。これにより、beforeAllフックにそのまま使用できます。CIに特に重要な2つのポイント:

  • Tunnelmoleはデフォルトで匿名のテレメトリ(Nodeバージョン、OS、クラッシュレポート)を収集します。ランナーでこれを無効にするには、環境変数TUNNELMOLE_TELEMETRY=0を設定します。
  • TUNNELMOLE_QUIET_MODE=1を設定すると、通常出力されるコンソールバナーを抑制し、CIログをすっきりさせます。
  • カスタムの安定したサブドメインは、有料プランまたはセルフホストインスタンスが必要です。無料プランは常にランダムなサブドメインを返し、エフェメラルなテスト実行には十分です。

ngrokの公式Node.js SDK

この資料の最初の草稿では、ngrokのNode SDKは”そのクローズドソースのGoバイナリをラップしている”と記述されていました。これは古い非公式のngrok npmラッパー(ngrok実行可能ファイルを子プロセスとしてダウンロード・起動するもの)に当てはまりますが、ngrokの公式SDK(@ngrok/ngrok)はバイナリを必要としないと公式に記載されています。これは、ngrokのRustライブラリ上に構築されたネイティブNode.jsバインディングであり、child_processのラッパーではありません。

const ngrok = require("@ngrok/ngrok");

(async function () {
  const listener = await ngrok.forward({
    addr: 8080,
    authtoken_from_env: true, // NGROK_AUTHTOKENを読み取る
  });

  console.log(`Ingress established at: ${listener.url()}`);
})();

ほとんどの機能には無料のngrokアカウントからのNGROK_AUTHTOKENが必要です。これはCIのシークレットに設定します。ただし、「バイナリをラップしている」という批判は、古いコミュニティパッケージに適用されるものであり、公式SDKには当てはまりません。

Pinggy:SSHがAPI、専用SDKではない

PinggyはngrokやLocalXposeのような専用のNode.js SDKを提供しません。提供されているのは:

  1. アクティブにメンテナンスされている公式CLI(npm install -g pinggy、Node.js 18+必須)。これにより、生成されたpinggy.link URLが標準出力に出力され、テストスクリプトから子プロセスとして起動可能です。
  2. それ以外に、標準のSSHリモートポートフォワーディングを自動化できるライブラリ(例:ssh2)を使ったシンプルな方法です: ssh -p 443 -R0:localhost:3000 a.pinggy.io

このコマンド(またはssh2ライブラリの対応コード)は、Pinggyの”API”の全てです。リバーストンネルが確立されると、公開URL(例:https://<ランダム>.pinggy.link)が返されます。CIでの実用的なポイント:無料プランはセッションを約60分に制限しますが、Webhookテストには十分です。ポート443(HTTPS)を使うのは、アウトバウンドHTTPS通信のみ許可されているランナーに特に有効です。

LocalXpose

以前の草稿では、LocalXposeの”プログラム的ライブラリサポート”は”特定の統合”を必要とすると記述していましたが、実際には公式のPromiseベースのNode.jsバインディングを提供しており、HTTP、TLS、TCP、UDPトンネルを同じクライアントオブジェクトからサポートしています:

const LocalXpose = require('localxpose');

// ゲストとしてレートリミット付きで動作、またはアクセス・トークンを設定
// (または環境変数LOCALXPOSE_ACCESS_TOKEN)
const client = new LocalXpose();

(async function () {
  const httpTunnel = await client.http({
    to: '127.0.0.1:3000',
    region: 'us', // us, ap, eu
  });

  console.log(`利用可能なURL: ${httpTunnel.addr}`);
})();

LocalXposeはUDPトンネルもサポートしており、HTTP以外のWebhookやゲームサーバ、IoTデバイスのシミュレーションなどに適しています。

Webhookの見逃せないリスク

なぜCI環境でプログラム的トンネルを使うのか?それはWebhookが静かに失敗し、見逃しが最も高価だからです。

現代のソフトウェアはイベント駆動の統合に大きく依存しています。チームは内部APIのユニットテストは徹底しますが、外部ベンダーのイベント処理について自動化されたテストはほとんど書きません。Stripeのタイムスタンプ形式の変更やGitHubの署名方式の変更があった場合、静的モックペイロードを使ったユニットテストは合格し続け、ビルドは緑色のままです。しかし、実運用では問題が発生します。

実際のトンネルを通じたエンドポイントテストは、実際のHTTP POSTリクエスト(ヘッダーや署名付きのリクエスト)を受信し、正しく処理されることを保証します。これにより、コードがメインブランチにマージされる前に問題を検出できます。

Node.jsでのプログラム的トンネル構築

以下は、JestやMochaのテストスイート内での例です。修正済みのTunnelmole APIを例にしています:

import { tunnelmole } from 'tunnelmole';
import app from '../src/app.js';
import http from 'http';

let server;
let publicUrl;

beforeAll(async () => {
  // 1. ローカルサーバを動的ポートで起動
  server = http.createServer(app);
  server.listen(3000);

  // 2. プログラム的にトンネルを確立
  publicUrl = await tunnelmole({ port: 3000 });

  console.log(`テスト環境公開URL: ${publicUrl}`);
});

afterAll(() => {
  // 3. クリーンアップ
  server.close();
  // Tunnelmoleはホスティングサービスの明示的な終了呼び出しは不要ですが、
  // ローカルHTTPサーバは閉じておくべきです。
});

publicUrlはテストスコープ内の変数なので、ヘッドレスブラウザやサードパーティAPI(Shopify、Slack、Stripe)に渡してテストイベントを送信できます。

GitHub ActionsでのWebhookテスト

プログラム的トンネルの最終目標は、完全なCI/CD統合です。アプリケーションを制御されたランナー内に隔離し、HTTPサーバを起動し、公開インターネットにトンネルし、実際のサードパーティWebhookをシミュレートします。典型的なパイプラインは4つのフェーズに分かれます:

フェーズ1 — 環境準備。 対象アプリと必要なバックエンドサービス(Postgres、Redis)をGitHubのネイティブサービスコンテナサポートを使って起動。

フェーズ2 — プログラム的トンネル確立。 Node.jsスクリプトがサーバを起動し、上記ライブラリのいずれかを使ってトンネルを開き、HTTPS URLを変数または環境出力として取得。

フェーズ3 — ペイロード投入。 スクリプトが実際のWebhookイベントをトリガーします。Stripeの場合、2つのStripe CLIコマンドを実行します。これには、stripe listen --forward-to "$EPHEMERAL_URL/webhooks/stripe"stripe trigger payment_intent.succeededが含まれます。--forward-tostripe listenのフラグです。stripe triggerは別のコマンドで、実際にStripe APIを呼び出してイベントを生成します。

フェーズ4 — 状態検証。 テストスイートはWebhookを受信したか待ち、200 OKを返すことを確認し、データベースの状態変化(例:サブスクリプションがactiveに変わったか)を検証します。

GitHub Actionsの例ワークフロー

name: Webhook統合テスト
on:
  pull_request:
    branches: [ main ]

jobs:
  test-webhooks:
    runs-on: ubuntu-latest

    steps:
      - name: コードのチェックアウト
        uses: actions/checkout@v6

      - name: Node.jsのセットアップ
        uses: actions/setup-node@v6
        with:
          node-version: '22'

      - name: 依存関係のインストール
        run: npm ci

      - name: Stripe CLIのインストール
        run: |
          curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg
          echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list
          sudo apt-get update && sudo apt-get install stripe

      - name: プログラム的トンネルとテストの実行
        env:
          STRIPE_API_KEY: ${{ secrets.STRIPE_TEST_KEY }}
        run: npm run test:webhooks

このワークフローでは、actions/checkoutactions/setup-nodeを最新のメジャーバージョン(v6)に更新しています。Node.jsのターゲットも20から22に変更(20は2026年4月にサポート終了)しています。Node 22は2027年4月までLTSです。Node 24も次のLTS候補です。

npm run test:webhooks内のJavaScriptがすべてを調整します:トンネルのオープン、stripe listenのバックグラウンド起動、stripe triggerの呼び出し、検証の実行。

CIトンネルのベストプラクティスとセキュリティ

CIランナーを公開インターネットに晒すことは、適切な管理が必要です:

厳格なエフェメラリティ。 テストが終わるまでトンネルを長時間放置しない。try/finallyafterAllフックを使って、トンネルとローカルサーバを積極的に閉じる。ハングしたジョブはリソースを浪費し、コストもかかります。

機密情報のマスク。 URLや出力に敏感な情報が含まれる場合、CIログから除去します。GitHub Actionsは::add-mask::コマンドをサポートしています:

echo "::add-mask::$EPHEMERAL_URL"

これにより、その後のログ出力から秘密情報が自動的に隠されます。add-maskは事前に登録しておく必要があります。@actions/corecore.setSecret()も利用可能です。

raw-bodyのパース検証。 本番環境で最も多いWebhook拒否の原因は、署名検証前にHTTPボディを変更するミドルウェアです。実際のトンネルは本物のHTTPトラフィックを通すため、StripeやGitHubが使うHMAC-SHA256署名のパースが正しく動作することを保証します。

同時実行とポート競合の管理。 CIジョブは並列実行されることが多いため、Node.jsサーバはlisten(0)でランダムな空きポートを割り当て、そのポートをトンネル設定に渡すのが安全です。

各ツールのセッション制限を理解。 無料プランはセッション時間を制限します(Pinggyは約60分)。Webhookテストは数秒から数分で完了しますが、遅いステージには注意が必要です。

まとめ

本格的なCI/CDを運用しているチームにとって、手動でURLを貼り付けてWebhookを検証する時代は終わりました。CLIバイナリからNode.jsのテストコード内のプログラム的トンネルに移行することで、ネットワークの入口もテスト可能なコードの一部となります。選択するライブラリは、完全オープンソースの自己ホスト可能なTunnelmole、成熟したngrokのSDK、シンプルなPinggyのSSH、UDPやマルチプロトコル対応のLocalXposeなどさまざまですが、結果は同じです。外部連携は、実際のHTTPトラフィックと署名付きリクエストを使って、顧客が「支払う」前に検証されます。


変更履歴

この文章は、事実確認のために公式ドキュメントやリポジトリを参照しながら書き直されました。主な変更点:

  1. メタデータやフォーマットの除去と、見出しやコードブロックを整えたMarkdownに再構成。
  2. Tunnelmoleのコード例修正。 以前のserve()の記述を削除し、tunnelmole()の正しいAPIとライセンス情報を追加。環境変数TUNNELMOLE_TELEMETRYTUNNELMOLE_QUIET_MODEの説明も追加。
  3. ngrok SDKの記述修正。 旧来のwraps its closed-source Go binaryの記述を削除し、公式の@ngrok/ngrokはバイナリ不要と明示。コード例も更新。
  4. LocalXposeの説明修正。 公式のPromiseベースNode.jsバインディングを紹介し、HTTP/TLS/TCP/UDPをサポートすることを明示。
  5. Pinggyの実態を明確化。 SDKはなく、CLIまたはSSHフォワーディングを使うと説明。無料プランの60分制限も記載。
  6. Stripe CLI例の修正。 --forward-tostripe listenのフラグであり、stripe triggerは別コマンドと明示。
  7. GitHub Actionsのバージョンアップ。 actions/checkoutactions/setup-nodeをv6に、Node.jsも22に変更。
  8. 信頼性の記述修正。 uptimeの問題ではなく、長期メンテナンスギャップとフォークの多さを根拠にした。
  9. その他の記述は正確性を維持し、変更なし。

タイトルとメタ情報も簡潔かつ自然な表現に調整済みです。

Continue from this article into the most relevant product guides and workflows.

Related Topics

#programmatic localhost tunnel, npm localtunnel alternative, webhook testing github actions, automated endpoint testing, localtunnel npm, localtunnel package, ephemeral urls, programmatic tunneling, continuous integration tunneling, ci/cd pipeline tunneling, github actions localtunnel, node.js localtunnel, automated webhook testing, integration test tunnel, spawn ephemeral endpoints, local tunnel automation, programmatic ngrok alternative, end to end webhook testing, automated API testing, ephemeral webhook endpoints, headless tunneling tool, ci pipeline local server, localtunnel vs ngrok, nodejs webhook testing, programmatic reverse proxy, cypress webhook testing, playwright webhook testing, automated webhook verification, dynamic tunnel URL, programmatic server tunneling, pipeline webhook testing, automated QA testing tools, continuous delivery tunneling, nodejs tunnel package, mock webhook testing, ci/cd endpoint validation, automated browser testing tunnel, github workflow webhook, programmable localhost tunnel, localtunnel alternative, ci cd webhook sandbox, testing webhooks in ci, temporary public url generator, automated regression testing tunnels, headless ngrok alternative, programmatic proxy setup, ci pipeline tunnel script, expose local server in ci, webhook automation testing, continuous integration endpoint testing, programmatic port forwarding, localtunnel integration tests, automated QA pipeline tunnel

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles