メインコンテンツまでスキップ

【実装】リバプロ

概要

Cloudflare Workers を使って リバースプロキシ(リバプロ) を実装する


全体像(通信フロー)

この実装では、 次の流れになります。

クライアント
→ Cloudflare(Workers)
→ オリジン(area11.org)


Workers の中で fetch() を使い、 オリジンへリクエストを転送します。


実装コード

以下が、今回のリバプロ実装です。

// Cloudflare Workers: Reverse Proxy
// - ORIGIN_HOST を変数(環境変数)として使用
// - アクセス元IPを X-Forwarded-For / X-Real-IP 等に格納
// - Host ヘッダーもオリジン向けに調整

export default {
/**
* @param {Request} request
* @param {{ ORIGIN_HOST: string }} env
* @param {ExecutionContext} ctx
*/
async fetch(request, env, ctx) {
if (!env?.ORIGIN_HOST) {
return new Response("Missing env.ORIGIN_HOST", { status: 500 })
}

const incomingUrl = new URL(request.url)

// オリジン宛URLを組み立て
const originUrl = new URL(request.url)
originUrl.hostname = env.ORIGIN_HOST
// 必要なら originUrl.protocol = "https:" の固定も可能

// クライアントIP取得(Cloudflareが付与)
// 代表例: CF-Connecting-IP
const clientIp =
request.headers.get("CF-Connecting-IP") ||
request.headers.get("True-Client-IP") ||
""

// ヘッダを複製して加工
const headers = new Headers(request.headers)

// 1) Host をオリジン用に差し替え
headers.set("Host", env.ORIGIN_HOST)

// 2) X-Forwarded-For を追記(既存があれば末尾に付与)
// 例: "既存, clientIp"
if (clientIp) {
const xff = headers.get("X-Forwarded-For")
headers.set("X-Forwarded-For", xff ? `${xff}, ${clientIp}` : clientIp)
headers.set("X-Real-IP", clientIp)
}

// 3) Forwarded / X-Forwarded-* を整備
headers.set("X-Forwarded-Host", incomingUrl.host)
headers.set("X-Forwarded-Proto", incomingUrl.protocol.replace(":", ""))
headers.set(
"X-Forwarded-Port",
incomingUrl.port || (incomingUrl.protocol === "https:" ? "443" : "80"),
)

// 任意: 由来が分かるヘッダー(運用・デバッグ用)
headers.set("X-Proxy-By", "cloudflare-worker")

// ボディありメソッドは body を渡す。
// Request.body はストリームなので、
// new Request(originUrl, request) で引き継ぐ形が簡単。
const originRequest = new Request(originUrl.toString(), {
method: request.method,
headers,
body: shouldHaveBody(request.method) ? request.body : null,
redirect: "manual",
})

// オリジンへ転送
const originResponse = await fetch(originRequest)

// レスポンスをそのまま返す(必要ならヘッダー加工も可能)
// Set-Cookie 等を触る場合は attributes や domain に注意
return originResponse
},
}

function shouldHaveBody(method) {
return !["GET", "HEAD"].includes(method.toUpperCase())
}

コードのポイント解説

  1. ORIGIN_HOST を環境変数にしている

コード中の env.ORIGIN_HOST が、 転送先オリジンのホスト名です。

環境ごとにオリジンを変えたい場合、 コードを書き換えずに切り替えられます。

  1. クライアント IP は CF-Connecting-IP を読む

Cloudflare はエッジで、 クライアント IP を CF-Connecting-IP として付与します。

Workers 側では、 その値を X-Forwarded-For / X-Real-IP に入れてオリジンへ渡します。

  • X-Forwarded-For は、 既存値がある場合に 既存, clientIp として 追記 しています。
  • 追記にしておくと、 多段プロキシ構成でも経路を残せます。
  1. Host をオリジン用に差し替える

オリジンがバーチャルホスト運用(Host でルーティング)している場合に効きます。

  • 接続先(originUrl.hostname
  • Host ヘッダー

を揃えると、 オリジン側は自然に処理できます。


セキュリティ上の注意点(重要)

  • WAF が無い場合、 Worker は入力検証を自動ではしてくれません
    • 公開 API なら WAF / Rate Limit / 認証 を併用推奨
  • X-Forwarded-For を信頼しすぎない
    • インターネットから来る X-Forwarded-For は偽装可能です
    • Workers では CF-Connecting-IP を元に設定し、 オリジン側は「Cloudflare 経由のリクエストだけ」このヘッダーを信頼する設計にします
  • Cookie / 認証周り
    • Set-CookieDomain / SameSite は構成によって破綻しやすいので注意

結果

workerの設定

設定

作成したリバプロ経由で無事アクセスできている。

作成したリバプロ

以上。