Development
13 min read
56 views

Embedded Tunnels: Spawning Ephemeral URLs Inside Your Integration Tests

IT
InstaTunnel Team
Published by the InstaTunnel team | Editorial policy
Embedded Tunnels: Spawning Ephemeral URLs Inside Your Integration Tests

Quick answer

Programmatic Tunnels: Spawning Ephemeral URLs in CI/CD Integ: 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.

For years, developers have treated localhost tunnels as a manual convenience — a CLI command run by hand to expose a web server for a quick client demo or a third-party API integration. But as software architecture leans further into event-driven systems and asynchronous APIs, that manual paradigm has become a bottleneck.

高度なQAやDevOpsチームは、stdoutからトンネルURLを抽出するシェルスクリプトから脱却し、トンネル提供者のネイティブSDKを使って一時的で安全な公開URLを直接統合テストスイート内で生成しています。インターネットのインゲスをシステムバイナリではなくソフトウェア依存として扱うことで、GitHub Actionsや他のCI/CDパイプラインでエンドツーエンドのWebhookテストを完全に自動化可能にしています。

この記事では、CLIハックからSDKベースのトンネリングへの移行、Node.jsでのプログラム的Webhookテストの正しい手順、そしてngrok SDKやnpmのlocaltunnelの代替案の現状について解説します。

CI/CD Webhookのジレンマ

自動化パイプラインでWebhook統合をテストするのは非常に難しいです。Stripeを使った決済やGitHubのプルリクエストに反応する統合など、外部プロバイダーが実際にHTTP POSTを送信しなければならない場合、エンドツーエンドのテストには外部側の送信が必要です。

しかし、GitHub ActionsやGitLab CIのようなCI/CD環境内でテストを実行すると、アプリケーションはNATやファイアウォールの背後にあるエフェメラルコンテナ内に孤立し、パブリックIPを持ちません。

一般的な回避策は二つありますが、どちらも完璧ではありません:

  • Webhookのモック化。 迅速ですが、モックは実際にプロバイダーが送信するペイロードフォーマットを正しく解析できていることを証明せず、署名検証やTLS交渉といったネットワークレベルのエッジケースをスキップします。
  • ステージング環境へのデプロイ。 静的ドメインのステージングサーバにデプロイし、そのドメインをWebhookプロバイダーに登録します。これにより、CIの原則である孤立性とアトミックなテスト実行が破られます。複数のプルリクエストを同時にテストしている場合、PR “A” のWebhookがPR “B” のテスト中にステージングサーバに届く可能性があります。

真の孤立性を得るには、各テスト実行ごとに一意で公開可能なURLが必要です。

パラダイムシフト:CLIハックからプログラム的トンネリングへ

初期の解決策は、bashスクリプト内でCLIツールをラップするものでした:グローバルにツールをインストールし、lt --port 8080 &のようにバックグラウンド実行し、grepawkでstdoutから生成されたURLを抽出します。これは脆弱です — バックグラウンドプロセスはCIランナー上でゾンビ化しやすく、localtunnelのようなツールは不安定さの記録があります(後述)。

より堅牢な方法はプログラム的トンネルです:シェルから別のバイナリに頼るのではなく、トンネルエージェントがSDKを通じてネイティブにテストプロセス内で動作します。例えばngrokは、Node.js、Go、Python、Rust向けのネイティブエージェントSDKを提供しています。同じプロセス内で動作させることで、以下が可能になります:

  • 非同期制御awaitでトンネルの作成を待ち、URLが確実に存在する状態でテストを進める
  • 動的登録 — 一時的なURLを文字列として取得し、StripeやTwilio、GitHubのWebhookエンドポイント登録APIに即座に渡す
  • 優雅なクリーンアップ — トンネルのクローズはテストフレームワークのクリーンアップフックに結びついた単一のメソッド呼び出しで完結し、孤立したバックグラウンドプロセスのリークを防ぐ

ステップバイステップ:Node.jsでのプログラム的Webhookテスト

以下は、Node.js、Jest、公式@ngrok/ngrokパッケージ(ネイティブSDK、NAPI-RSベース)を使った具体例です。

セットアップ

npm install --save-dev jest express @ngrok/ngrok axios

統合テスト

// webhook.test.js
const express = require('express');
const ngrok = require('@ngrok/ngrok');
const axios = require('axios');

describe('エンドツーエンドWebhook処理', () => {
  let server;
  let listener;
  let publicUrl;
  let receivedPayload = null;

  beforeAll(async () => {
    // 1. ローカルサーバの起動
    const app = express();
    app.use(express.json());

    app.post('/webhook', (req, res) => {
      receivedPayload = req.body;
      res.status(200).send('Webhook受信');
    });

    server = app.listen(8080);

    // 2. プログラム的にトンネルを生成
    listener = await ngrok.forward({
      addr: 8080,
      authtoken_from_env: true,
    });

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

  afterAll(async () => {
    // 3. 優雅なクリーンアップ
    if (listener) await listener.close();
    if (server) server.close();
  });

  it('ライブWebhookを受信・処理できるか', async () => {
    // 4. 一時URLをサードパーティAPIに登録
    await axios.post('https://api.thirdparty.com/v1/webhooks', {
      target_url: `${publicUrl}/webhook`,
      events: ['resource.created'],
    }, {
      headers: { Authorization: `Bearer ${process.env.API_KEY}` },
    });

    // 5. サードパーティ側でイベントをトリガー
    await axios.post('https://api.thirdparty.com/v1/resources', {
      name: 'Test Resource',
    }, {
      headers: { Authorization: `Bearer ${process.env.API_KEY}` },
    });

    // 6. Webhookが届くまで待つ
    await new Promise(resolve => setTimeout(resolve, 3000));

    // 7. ペイロードが正しく受信されたか検証
    expect(receivedPayload).toBeDefined();
    expect(receivedPayload.event_type).toBe('resource.created');
  });
});

注意点: SDKのforward()は、ローカルフォワードとngrokセッションの両方を閉じる.close()メソッドを持つリスナーオブジェクトを返します。ngrok.disconnect(url)のようなトップレベルのAPIはなく、@ngrok/ngrokの公式APIに従います。(古いngroknpmラッパーのngrok.disconnect()とは異なるため注意してください。)

GitHub ActionsでのWebhookテストの極意

name: プログラム的トンネルを使った統合テスト

on:
  pull_request:
    branches: [ main ]

jobs:
  test-webhooks:
    runs-on: ubuntu-latest
    steps:
      - name: コードのチェックアウト
        uses: actions/checkout@v4

      - name: Node.jsのセットアップ
        uses: actions/setup-node@v4
        with:
          node-version: '24'
          cache: 'npm'

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

      - name: Webhook統合テストの実行
        env:
          NGROK_AUTHTOKEN: ${{ secrets.NGROK_AUTHTOKEN }}
          API_KEY: ${{ secrets.THIRD_PARTY_API_KEY }}
        run: npm run test:integration

(Node 24は現在のActive LTSラインです。Node 20は2026年4月にサポート終了予定です。)

重要なCI/CDのポイント

  • 同時実行制限。 複数のPRが同時に走ると複数のトンネルが必要です。プロバイダーの同時エンドポイント制限を確認してください。
  • レートリミット。 GitHubやSlackのAPI呼び出しにはレート制限があります。Webhookの登録・解除を頻繁に行うとクォータを超える可能性があるため、専用のテストアカウントや、エンドツーエンドのブランチのみでライブトンネルを使い、ユニットテストではモックを検討してください。
  • サンドボックス環境の利用。 本番外のAPIやデータに触れないように、Stripe Test ModeやGitHubのサンドボックス組織を使いましょう。
  • 安全なクリーンアップ。 afterAllt.Cleanupフックでトンネルのライフサイクルを管理し、失敗してもエンドポイントが残らないようにします。
  • 固定のスリープに頼らない。 Webhookの遅延は変動するため、setTimeoutではなく、ペイロード到達を待つ仕組みを使いましょう。

2026年の展望:プログラム的代替案の評価

1. ngrok SDKs(4言語対応のネイティブSDK)

ngrokはGo、Rust、Python、JavaScript向けのエージェントSDKを提供しており、別のバイナリは不要です。GoはAPI v2のリニューアルを最初に受け、Forward()の簡素化や統一されたイベント処理、log/slogによる構造化ロギングを導入しています。各言語SDKは用語も統一されつつあり、エンドポイント、エージェント、トラフィックポリシーといった概念が共通化されています。

比較例:Node.jsの例と比べたGoの最小例

package main

import (
	"context"
	"log"

	"golang.ngrok.com/ngrok/v2"
)

func main() {
	fwd, err := ngrok.Forward(context.Background(),
		ngrok.WithUpstream("http://localhost:8085"),
	)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("利用可能:", fwd.URL())
	select {}
}

Python例:

import ngrok

forwarder = ngrok.forward("localhost:8085", authtoken_from_env=True)
print(f"利用可能:{forwarder.url()}")

メリット: 4言語すべてでネイティブに動作し、成熟したドキュメント、IP制限や負荷分散、レート制限のトラフィックポリシーエンジン、OAuth/OIDCやWebhook署名検証も標準搭載。

無料プランの注意点: ngrokの公式ドキュメントによると、無料エンドポイントはセッションタイムアウトなしで、無期限にバックグラウンドで動作可能です。ただし、1つの開発用ドメイン、最大3つの同時オンラインエンドポイント、月1GBの帯域、20,000リクエスト/月の制限があります。よく誤解される「2時間の無料セッションタイムアウト」は誤りで、第三者の比較コンテンツ由来の誤情報です。

デメリット: 無料プランの3エンドポイント/3エージェントの同時実行制限は、多数のPRを並列でテストするCIパイプラインではボトルネックになり得ます。より多く使いたい場合は有料プランに移行してください。

2. InstaTunnel

InstaTunnel(instatunnel.my)は、実際に開発されているトンネルサービスで、公開CLIリポジトリ(npm install -g instatunnel)、ホストされたダッシュボード、AIエージェント向けのMCPエンドポイントサポートもあります。

比較検討のために注意点:公式ブログやMediumに掲載されている、24時間無料セッション、3つの無料同時トンネル、無料サブドメイン、「ngrok Proより50%安い」といった数字は、ベンダー自身の情報源です。独立した比較ではなく、最新の料金ページを確認してください。ngrokと同様に、無料プランの制限に関する情報は公式のものを優先しましょう。

3. Webhook Relay

Webhook Relayは、ポートフォワーディングだけでなく、Webhookの配信側から受信側へのルーティングも行います。外部エージェントを通じて、ローカルHTTPサービスやプライベートネットワーク、KubernetesサービスにWebhookを中継します。変換やフィルタリング、スロットリング、リプレイもサポート。

誤解の訂正: 一方向のWebhookフォワーディングだけではなく、双方向のTCP/TLSトンネルもサポートしており、ローカルHTTPサービスの公開も可能です。SOC 2 Type II認証済みで、セルフホストも選択可能です。

4. Cloudflare Tunnel (cloudflared)

Cloudflareを利用している場合、Cloudflare Tunnelは無料で信頼性の高いゼロトラストルーティングを提供します。

メリット: 無料で帯域制限なし、Cloudflareのネットワークを利用し、WAFやDDoS保護、ロードバランサとも連携可能。

デメリット: 公式SDKはなく、cloudflaredバイナリをサブプロセスとして起動する必要があります。今のところ、cloudflaredのGo SDKは公式には存在しません(cloudflare/cloudflaredのGitHubの要望にて要望中)。そのため、純粋なインプロセスSDKとしての統合は難しく、trycloudflare.comのトンネルは保証された稼働時間がなく、あくまで一時的なテスト用途に留まります。

localtunnelについての補足

オープンソースのnpmパッケージlocaltunnelは、2021年以降リリースされておらず、単一のメンテナによって管理されており、axiosの高重大度の未解決脆弱性(CSRFやSSRFに関する問題)があります。これにより、CIパイプラインでの使用は推奨されません。単なる信頼性の問題だけでなく、セキュリティリスクも考慮してください。

Ephemeral CI/CDトンネルのベストプラクティス

  1. 安全なクリーンアップ。 afterAllt.Cleanupで必ずトンネルを閉じ、失敗したテストでエンドポイントが残らないように。
  2. ポーリングを利用。 Webhook遅延は変動するため、受信を待つ仕組みを導入しましょう。
  3. サンドボックスを利用。 プロバイダーのテストモードを使い、CIのWebhookが本番データに触れないように。
  4. ボトルネックに合わせたツール選定。 ngrokの無料制限に引っかかる場合は、代替や有料プランを検討してください。

結論

端末出力からトンネルURLを抽出する必要はもうありません。ネイティブエージェントSDK(ngrokは4言語対応、Webhook RelayやCloudflare、InstaTunnelなども)を使えば、インゲスをソフトウェア依存として直接管理でき、beforeAll/afterAllのライフサイクルに結びつけられます。選択したツールの制限(セッション長、同時接続数、価格)を事前に確認し、CIの前提条件として誤解しないようにしましょう。


チェンジログ

メタデータの削除: コードブロックの言語ラベルを除去し、すべてのコード例を適切なフェンス付きブロックに再構築。

修正点: 1. Teardown APIの誤り — 元のNode.js例ではngrok.disconnect(publicUrl)を呼び出していましたが、これは古いngroknpmラッパーのAPIです。正しくはawait listener.close()です(@ngrok/ngrokの公式APIに従う)。 2. Node.jsバージョンの更新 — Node 20からNode 24に変更(2026年4月にサポート終了のため)。 3. ngrok無料プランの制限 — 公式ドキュメントに基づき、3エンドポイント、1ドメイン、1GB/月、20,000リクエスト/月、セッションタイムアウトなしと確認。誤情報だった「2時間のセッションタイムアウト」を修正。 4. 有料プランの更新 — Hobbyistは月$10(年$8/月)、従量課金は月$20から。 5. InstaTunnelの記述見直し — 実在し、積極的に開発されている製品であることを明示し、比較の数字はベンダーの情報源に基づくと説明。 6. Webhook Relayの誤解 — 一方向だけでなく双方向のTCP/TLSトンネルもサポートしていることを追記。 7. Cloudflare Tunnel SDKの記述 — GitHubの要望によりGo SDKは現状未実現であることを確認。 8. localtunnelの信頼性について — 2021年以降のリリースなし、メンテナは一人、未解決の脆弱性が存在することを明示。

追記: - GoとPythonのSDK例を追加し、ngrokのAPI v2の刷新とSDK間の用語統一についても言及。 - 「ツールを実際のボトルネックに合わせて選ぶ」指針を明示し、価格ではなく並列数の制限に焦点を当てるよう促す。

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

Related Topics

#programmatic localhost tunnel, webhook testing github actions, npm localtunnel alternative, ngrok sdk alternative, embedded localhost tunnel, ephemeral urls integration tests, programmatic tunnel nodejs, programmatic tunnel golang, programmatic tunnel python, automated webhook callback testing, ci cd local tunnel, github actions webhook testing, ephemeral tunnel url, test webhooks programmatically, programmatically expose localhost, embedded reverse proxy sdk, integration test webhook callback, automated integration testing webhooks, ngrok agent sdk, ngrok nodejs sdk alternative, localtunnel npm alternative, programmatic port forwarding, developer testing automation, devops webhook automation, ephemeral public endpoints, e2e webhook testing, cypress webhook testing, playwright webhook testing, jest webhook testing, ci cd pipeline ephemeral tunnel, ephemeral environment testing, temporary webhook url, automated tunnel creation, webhook testing pipeline, software testing reverse proxy, headless tunneling tool, programmatic tunnel library, node js webhook testing, golang webhook tunnel, python webhook tunnel, test third party webhooks ci cd, live webhook testing integration tests, programmatically open tunnel, ephemeral server url, containerized webhook testing, docker integration test tunnel, github workflow webhook tunnel, programmatic ngrok alternative, spawn ephemeral url, automated testing infrastructure, temporary public url SDK, gitlab ci webhook tunnel, programmatic webhook proxy

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