KamuiDashでは、テナントごとのアプリケーションと独自ドメインを、ひとつのCloudflareエッジで受けています。
この記事では、利用者のリクエストが入口に届いてから、テナントアプリの応答として返るまでを順にたどります。
公開入口からテナントアプリまで
すべてのHTTPリクエストは、まずCloudflare Workerに届きます。WorkerはHostから対象アプリを解決し、動的アプリならCloudflare Tunnelを通じて、クラスタ内の内部ルーターとテナントアプリへ渡します。
入口のWorkerがドメイン解決と経路選択を持ち、実行が必要な動的リクエストだけをクラスタまで送ります。
1. WorkerでHostを解決する
Workerは受信したHostを正規化し、KVにあるドメインと内部アプリの対応表を引きます。独自ドメインもプラットフォームのサブドメインも、この時点では同じように「どのアプリを指すか」を解決する入力です。対応表にない外部ドメインは、クラスタへ流さずWorkerで404を返します。
アプリが特定できたら、Workerは公開種別を確認します。エッジで応答を完結させない場合は、動的アプリの実行先を引いてTunnelへ渡します。Workerが読むKVは、用途ごとに分けています。
ドメイン対応 Host → 内部アプリ名
実行先レジストリ 内部アプリ名 → 動的アプリの実行先ドメイン対応と動的アプリの実行先は、更新頻度も反映許容時間も異なるため、同じレコードにはしていません。
- 01ホスト名を解決独自ドメインを内部アプリへ対応付ける
- 02公開種別を確認動的リクエストだけをクラスタへ送る
- 03動的な実行先を解決アプリの配置先からTunnel経路を選ぶ
- 04失敗を境界で正規化タイムアウト・上流エラー・追跡IDを一貫させる
2. 動的リクエストはTunnelを通って内部ルーターへ進む
エッジで応答を完結させない場合、Workerはアプリと実行先の対応表をKVから読み、該当するTunnelの経路を選びます。そこで解決したアプリ識別子と実行先の文脈をリクエストへ付けてTunnelへ送ります。クライアントから届いた同名の情報は、そのまま使わずWorkerの解決結果で置き換えています。
転送時には、受信したリクエストヘッダーを基に新しい上流リクエストを組み立てます。その際にHostとルーティング文脈をWorkerの解決結果で明示的に設定し、リクエストIDも付与します。テナントの選択を、クライアントが送った任意のヘッダー値に委ねないためです。
Tunnelコネクタは外向きにCloudflareと接続しており、クラスタ側にインターネットから到達できる受信口を持ちません。Tunnelの先にある内部ルーターがWorkerから渡された文脈を受け取り、対象のテナントアプリへ転送します。
Workerから上流へのfetchはAbortControllerで時間を区切っています。接続不能・タイムアウト・上流のサーバーエラーは、入口でゲートウェイエラーに変換します。応答に含まれる内部向けのルーティング情報は削除し、アプリがCache-Controlを返さない動的応答には共有キャッシュしない既定値を設定します。WebSocketのアップグレードは、通常のHTTP応答と別にそのまま中継します。
3. Tunnelの先でも入口を限定する
内部ルーターはWorkerが付与したルーティング情報を使うため、Tunnelを通ったリクエストだけを受け取る構成にしています。KamuiDashでは、内部ルーターへのIngressをTunnelコネクタのPodに限定するNetworkPolicyを適用しています。
このポリシーでは、Tunnelコネクタだけを送信元として許可しています。これにより、同じクラスタ内の別のワークロードが内部ルーターへ直接到達し、Workerが解決するはずの文脈を偽装する経路を閉じています。公開入口でのHost解決と、クラスタ内での受信元制限を、同じリクエスト経路の両端に置いています。
4. ドメイン登録とデプロイで変わるもの
独自ドメインを追加するときは、Cloudflareのカスタムドメイン機能で所有確認と証明書発行を通した後に、ドメインと内部アプリの対応を登録します。削除時には、その対応とドメイン側の状態を順に解除します。
動的アプリの移動では、実行先レジストリの対応が変わります。ドメイン対応と実行先は更新頻度が異なるため、別々にキャッシュ時間を設定しています。
KVは書き込みによってすべてのエッジキャッシュが即時に消えるストアではなく、未登録という結果も短時間残ります。登録や移動の処理では、DNS・証明書・KV反映までを含めて状態を追います。WorkerはリクエストIDとエッジ側の追跡情報を構造化ログに残し、認証情報やCookieは記録しません。Tunnel、内部ルーター、テナントアプリまでを、同じリクエストIDで追跡します。
この経路でCloudflareに任せていること
独自ドメインでは、カスタムホスト名の所有確認と証明書の発行・更新をCloudflareに任せています。KamuiDash側で持つのは、そのドメインをどのテナントアプリへ結び付けるかという対応情報です。ドメインごとに証明書を発行し、公開入口を追加する処理をアプリケーション基盤で個別に持たずに済んでいます。
Workerはすべての公開リクエストが通る共通の実行地点です。Hostの解決、上流リクエストの組み立て、エラー応答の正規化、リクエストIDの付与をここでまとめています。テナントアプリごとに同じ入口処理を実装する必要がありません。
Tunnelでは、クラスタ側のコネクタが外向きに接続を張ります。そのため、テナントアプリや内部ルーターにインターネットから直接到達するための公開受信口を持たせずに、Workerからクラスタへリクエストを渡せています。受信元を限定するNetworkPolicyはKamuiDash側で持ち、Cloudflareからクラスタへ入る経路はTunnelに集約しています。
まとめ
KamuiDashの公開経路では、次の三つをCloudflareの入口に集約しています。
- Hostからテナントアプリを解決する — 独自ドメインとプラットフォームのサブドメインを同じ対応表で扱い、Workerで行き先を決めています。
- 解決済みの文脈だけをクラスタへ渡す — Workerで上流リクエストを組み立て、Tunnelと内部ルーターを通して対象のテナントアプリへ届けます。
- 変更も配信経路の一部として扱う — ドメイン登録やアプリ移動では、証明書・KVキャッシュ・経路の反映までを同じ流れで追います。
Cloudflareを入り口に置くことで、テナントごとに公開経路を持たせず、Worker、Tunnel、内部ルーターの役割を分けています。
KamuiDashの設計思想や、GitHubからデプロイする基本的な流れについてはKamuiDashを使う理由で説明しています。