在 Cloudflare Tunnel 後方執行
Cloudflare Tunnel 由源站上的 cloudflared 主動連線至 Cloudflare,再透過該連線接收請求。源站不需要開放公開連接埠;TLS 在 Cloudflare 邊緣終結,源站透過 loopback 接收明文 HTTP。本頁說明 Tunnel 設定,以及如何記錄實際用戶端位址。
📌 本頁描述 v0.2.2。
🧾 開始之前
Section titled “🧾 開始之前”- 網域已在 Cloudflare 帳號中,且可以使用 Zero Trust。
cloudflared與 Pingclair 在同一台主機上,且 Pingclair 正在提供網站(提供靜態網站)。- 使用儀表板(Zero Trust → Networks → Tunnels),或一個對該 zone 具有 Cloudflare Tunnel: Write 與 DNS: Edit 權限的 API token。這裡的範例使用 API,並把
$CF_TOKEN、$ACCOUNT與$ZONE分別設為 token、帳號 ID 與 zone ID。
🌐 建立 tunnel
Section titled “🌐 建立 tunnel”curl -s -X POST -H "Authorization: Bearer $CF_TOKEN" -H 'Content-Type: application/json' \ --data '{"name":"docs-origin","config_src":"cloudflare"}' \ "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT/cfd_tunnel"{"success":true,"result":{"id":"bc6869fa-19cf-4780-b95b-f11be77eb329","name":"docs-origin", …}}config_src: cloudflare 代表這個 tunnel 是 遠端管理 的:它的 ingress 規則存放在 Cloudflare,透過 API 推送,所以 connector 旁邊不需要寫任何檔案。
connector 的憑據要另外呼叫取得:
curl -s -H "Authorization: Bearer $CF_TOKEN" \ "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT/cfd_tunnel/$TUNNEL_ID/token"這個 token 是機密:任何主機拿到它都能加入這個 tunnel。請把它當成密碼看待,外洩時要輪替。
🔌 連接主機
Section titled “🔌 連接主機”curl -fsSL -o /tmp/cloudflared.deb \ https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.debsudo dpkg -i /tmp/cloudflared.debsudo cloudflared service install "$TUNNEL_TOKEN"INF Linux service for cloudflared installed successfullyconnector 會向附近的 Cloudflare 據點開啟四條連線,預設透過 QUIC:
INF Registered tunnel connection connIndex=2 … location=pdx02 protocol=quicINF Registered tunnel connection connIndex=3 … location=sea10 protocol=quic🌍 路由一個主機名稱
Section titled “🌍 路由一個主機名稱”ingress 規則決定哪個主機名稱會連到哪個源站服務:
curl -s -X PUT -H "Authorization: Bearer $CF_TOKEN" -H 'Content-Type: application/json' \ --data '{"config":{"ingress":[ {"hostname":"tunnel-test.pingclair.com","service":"http://127.0.0.1:80"}, {"service":"http_status:404"}]}}' \ "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT/cfd_tunnel/$TUNNEL_ID/configurations"最後一條是全部接住的規則:任何其他主機名稱的請求都會得到 404,而不會抵達源站。
接著把名稱指向 tunnel,並開啟代理:
curl -s -X POST -H "Authorization: Bearer $CF_TOKEN" -H 'Content-Type: application/json' \ --data '{"type":"CNAME","name":"tunnel-test.pingclair.com","content":"'$TUNNEL_ID'.cfargotunnel.com","proxied":true,"ttl":60}' \ "https://api.cloudflare.com/client/v4/zones/$ZONE/dns_records"從任何地方:
curl -I https://tunnel-test.pingclair.com/HTTP/2 200content-type: text/html; charset=utf-8accept-ranges: bytesserver: cloudflareserver: cloudflare 表示回應的是邊緣。源站是透過 tunnel 連到的,沒有為它開放任何對內連接埠。
🎯 讓源站看見用戶端
Section titled “🎯 讓源站看見用戶端”每個請求都是從 loopback 上的 connector 抵達,所以存取日誌預設記錄的是 connector,而不是用戶端:
📝 Access … host="tunnel-test.pingclair.com" status=200 remote_ip=127.0.0.1 user_agent="curl/8.7.1"trusted_proxies 列出可以在轉送標頭中聲明用戶端位址的對端。connector 跑在同一台主機上,所以清單只需要 loopback:
{ admin 127.0.0.1:2019 servers { trusted_proxies static 127.0.0.1/32 client_ip_headers CF-Connecting-IP }}
http://:80 { root * /srv/site file_server}以同一個請求在加上這個選項前後實測:
remote_ip=127.0.0.1 # beforeremote_ip=16.162.199.171 # after: the client that started the request依用戶端的速率限制與 client_ip 匹配器,也是靠這個設定才能在 tunnel 後方看見真正的用戶端。它在啟動時讀取,所以變更後需要重啟,而不是重載(重載意味著什麼)。
client_ip 與 {client_ip} 使用所列標頭中的用戶端;remote_ip 與 {remote_host} 仍是 connector 的位址。只有受信任的對端能提供這些標頭。CF-Connecting-IP 必須明確列入 client_ip_headers。
⚠️ 無法運作時
Section titled “⚠️ 無法運作時”HTTP/2 530並帶有error code: 1033。 這個 tunnel 沒有 connector。在源站上執行systemctl is-active cloudflared可以知道它是否在執行;connector 註冊後幾秒內,請求就會恢復回應200。- 請求連到了別的網站,或得到
404。 ingress 規則依序匹配,最後是全部接住的規則;怪罪 DNS 之前,先檢查規則中的主機名稱拼寫。 - 邊緣回傳
502。 connector 正常,但源站服務拒絕了連線:Pingclair 沒有在規則指定的連接埠上監聽。 - 存取日誌永遠顯示
127.0.0.1。 缺少trusted_proxies,如上所述。 - 主機名稱無法解析。 這筆記錄必須是指向
<tunnel-id>.cfargotunnel.com且開啟代理的 CNAME;灰色雲朵的記錄會完全繞過 tunnel。 - connector token 外洩了。 輪替 tunnel 的 token,並用新的 token 重新安裝服務。
- 提供靜態網站:這些範例指向的源站。
- TLS:可以調整什麼:當邊緣不終結 TLS 時,源站能用憑證做什麼。
- 以服務方式執行:源站上的 unit,以及
trusted_proxies那段提到的重載語意。
