ngrokの魔法を解き直す ── 仕組みを理解し、Goで自作してみる
ngrokがlocalhostを世界に出している仕組みを、NAT越え・muxado多重化・エッジ処理の三層モデルで解き明かし、Goで200行のクローンを段階的に育てながら理解するシリーズ。
ngrokの魔法を解き直す ── 仕組みを理解し、Goで自作してみる
このシリーズが解決すること
ngrok http 3000 と打つだけで、家の Wi-Fi に繋がった自分のラップトップが、いきなり全世界からアクセスできる HTTPS の URL を持つ。便利だが、裏で何が起きているのか説明できる人は意外と少ない。
- 「ファイアウォール内のサーバーが、なぜ外部からのリクエストを受けられるのか不思議」
- 「Cloudflare Tunnel や Tailscale Funnel との違いを技術的に説明できない」
- 「自分で似たものを作れる気がしない」
このシリーズは、その「魔法に見える」状態を終わりにするためのものです。
読み終えるとできるようになること
- ngrok の裏側で起きている通信を、永続コントロールコネクション + 多重化されたデータコネクション + TLS 終端付きエッジルーター の三層モデルで説明できる
- 自分で 200 行程度の HTTP リバーストンネル を Go で書ける
- Cloudflare Tunnel・frp・bore・Tailscale Funnel などを「設計の選択肢」として比較評価できる
- NAT の非対称性が「リバーストンネルが成立する根拠」になっていることを RFC レベルで説明できる
このシリーズの対象
| 項目 | 内容 |
|---|---|
| 対象読者 | ngrok を実務で使ったことがある Web / バックエンド開発者 |
| 前提知識 | TCP/TLS の基本、HTTP/1.1 の基本、Go の基本構文 |
| 難易度 | ★★★☆☆(中級) |
| 読了時間 | 本編 約 2.5 時間 / 付録含め 約 3.5 時間 |
| 対象バージョン | ngrok agent config v3、golang.ngrok.com/muxado/v2 v2.0.1、Go 1.23+ |
| 構成 | 本編 9 章 + 付録 2 本 |
シリーズ構成
スパイラル型で組み立てています。毎章コードが少しずつ育ち、第 6 章までに本物の ngrok に近い「型付き多重化トンネル」が手元に完成する設計です。
| 章 | タイトル | 何をするか |
|---|---|---|
| 1 | プロローグ:ngrok http 3000 の魔法を、自分の手で解き直す | シリーズの読み方とゴールを共有 |
| 2 | NAT の非対称性を解剖する | なぜ localhost が世界に出ないのか、conntrack と RFC の話 |
| 3 | 80 行の Go で ssh -R を再発明する | 最も素朴なリバーストンネルを動かす |
| 4 | 1 本の TCP に複数の会話を流す | muxado でストリーム多重化を導入 |
| 5 | ホスト名で振り分ける | HTTP ルーティングと x-forwarded-* |
| 6 | コントロールとデータを分ける | TypedStreamSession で型付け多重化 |
| 7 | 本物の ngrok と答え合わせする | GSLB・Traffic Policy・Agent Endpoint |
| 8 | 同じ問題を違う設計で解く | Cloudflare Tunnel・frp・bore・Tailscale Funnel との比較表 |
| 9 | エピローグ:トンネリングの未来を展望する | MCP/AI Gateway 時代のトンネルと参考文献 |
| 付録 A | TLS 終端と SNI ルーティングを実装する | 本編で省いた TLS 周辺 |
| 付録 B | 同じトンネルを yamux と HTTP/2 で書き直す | muxado との設計対比 |
読み方ガイド
- 「使ったことはあるが中身は知らない」読者 は、第 1 章から順に読むのがおすすめです。3 章以降は前章のコードを増築していくため、飛ばすとコンテキストが切れます
- プロトコル設計に興味がある読者 は、第 2 章・第 4 章・第 6 章・付録 B が中心的な読み所です
- 競合プロダクトとの比較が知りたい読者 は、第 8 章だけ単独で読んでも価値があります
参考にしたソース
主要な一次情報は最終章(第 9 章)でまとめて掲載します。本シリーズは公式ドキュメント・公式リポジトリ・関連 RFC を一次情報として参照し、必要に応じて創業者 Alan Shreve のポッドキャストや公式ブログから直接引用しています。
それでは、第 1 章から始めましょう。
目次
- プロローグ:`ngrok http 3000` の魔法を、自分の手で解き直す シリーズの読み方とゴールを共有する導入章。「魔法を解く旅」の地図を渡す。
- NAT の非対称性を解剖する —— なぜ localhost は世界に出ないのか conntrack の非対称性と関連 RFC を解剖し、リバーストンネルが成立する理論的根拠を押さえる。
- 80 行の Go で `ssh -R` を再発明する NAT を内側から裏返す最小実装。agent → server の outbound 1 本だけで、外部リクエストを localhost に届ける 80 行の Go コードを書く。
- 1 本の TCP に複数の会話を流す —— muxado でストリーム多重化を導入する ch03 の素朴な実装が抱える「TCP 1 本=同時 1 リクエスト」の制約を、muxado による論理ストリーム多重化で解消する。HTTP/2 のフレーム層を削ぎ落とした 4 種類のフレームと、`net.Listener` を実装する Session の妙を体感する。
- ホスト名で振り分ける —— HTTP ルーティングと `x-forwarded-*` を実装する 公開 URL のホスト名から agent を引き、`x-forwarded-*` を付けて upstream に流す「エッジの正体」を 40 行で再現する。
- コントロールとデータを分ける —— `TypedStreamSession` で型付け多重化する muxado.TypedStreamSession でストリームに型 ID を付け、コントロールチャネルとデータチャネルを分離する。本物の ngrok と同じプロトコル系統まで自作版を引き上げる。
- 本物の ngrok と答え合わせする —— GSLB・Traffic Policy・Agent Endpoint 自作 mintunnel と本物の ngrok を並べ、省略した要素・別実装の要素・偶然一致した要素を答え合わせする。
- 同じ問題を違う設計で解く —— 競合トンネリングプロダクトを比較する localhost を世界に出す同じ問題を、6 プロダクトがどう違う設計で解いているかを 3 つの設計軸で比較する。
- エピローグ:トンネリングの未来を展望する シリーズで得た知識でプロローグの 3 つの問いに答え、MCP / AI Gateway / Zero Trust / QUIC への発展を展望する締めくくり。
- 付録 A:TLS 終端と SNI ルーティングを実装する 本編で HTTP に絞った mintunnel に、エッジでの TLS 終端・SNI ベースのルーティング・autocert による Let's Encrypt 自動発行を後付けする付録。
- 付録 B:同じトンネルを yamux と HTTP/2 で書き直す ch06 までで書いた muxado 版 mintunnel を、hashicorp/yamux 版と golang.org/x/net/http2 版に書き換えて並べる。3 つのライブラリの API・フレーム数・HTTP semantics の有無を実コードで対比し、ngrok がなぜ muxado を選んだのかを「書いてみて」体感する付録。