# ☁️ 在 Cloudflare Tunnel 後方執行 Cloudflare Tunnel 由源站上的 `cloudflared` 主動連線至 Cloudflare,再透過該連線接收請求。源站不需要開放公開連接埠;TLS 在 Cloudflare 邊緣終結,源站透過 loopback 接收明文 HTTP。本頁說明 Tunnel 設定,以及如何記錄實際用戶端位址。 📌 本頁描述 **v0.2.2**。 ## 🧾 開始之前 - 網域已在 Cloudflare 帳號中,且可以使用 Zero Trust。 - `cloudflared` 與 Pingclair 在同一台主機上,且 Pingclair 正在提供網站([提供靜態網站](/zh-TW/guides/static-site/))。 - 使用儀表板(Zero Trust → Networks → Tunnels),或一個對該 zone 具有 **Cloudflare Tunnel: Write** 與 **DNS: Edit** 權限的 API token。這裡的範例使用 API,並把 `$CF_TOKEN`、`$ACCOUNT` 與 `$ZONE` 分別設為 token、帳號 ID 與 zone ID。 ## 🌐 建立 tunnel ```bash 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" ``` ```text {"success":true,"result":{"id":"bc6869fa-19cf-4780-b95b-f11be77eb329","name":"docs-origin", …}} ``` `config_src: cloudflare` 代表這個 tunnel 是 **遠端管理** 的:它的 ingress 規則存放在 Cloudflare,透過 API 推送,所以 connector 旁邊不需要寫任何檔案。 connector 的憑據要另外呼叫取得: ```bash curl -s -H "Authorization: Bearer $CF_TOKEN" \ "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT/cfd_tunnel/$TUNNEL_ID/token" ``` 這個 token 是機密:任何主機拿到它都能加入這個 tunnel。請把它當成密碼看待,外洩時要輪替。 ## 🔌 連接主機 ```bash curl -fsSL -o /tmp/cloudflared.deb \ https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb sudo dpkg -i /tmp/cloudflared.deb sudo cloudflared service install "$TUNNEL_TOKEN" ``` ```text INF Linux service for cloudflared installed successfully ``` connector 會向附近的 Cloudflare 據點開啟四條連線,預設透過 QUIC: ```text INF Registered tunnel connection connIndex=2 … location=pdx02 protocol=quic INF Registered tunnel connection connIndex=3 … location=sea10 protocol=quic ``` ## 🌍 路由一個主機名稱 ingress 規則決定哪個主機名稱會連到哪個源站服務: ```bash 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,並開啟代理: ```bash 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" ``` 從任何地方: ```bash curl -I https://tunnel-test.pingclair.com/ ``` ```text HTTP/2 200 content-type: text/html; charset=utf-8 accept-ranges: bytes server: cloudflare ``` `server: cloudflare` 表示回應的是邊緣。源站是透過 tunnel 連到的,沒有為它開放任何對內連接埠。 ## 🎯 讓源站看見用戶端 每個請求都是從 loopback 上的 connector 抵達,所以存取日誌預設記錄的是 connector,而不是用戶端: ```text 📝 Access … host="tunnel-test.pingclair.com" status=200 remote_ip=127.0.0.1 user_agent="curl/8.7.1" ``` `trusted_proxies` 列出可以在轉送標頭中聲明用戶端位址的對端。connector 跑在同一台主機上,所以清單只需要 loopback: ```caddyfile { 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 } ``` 以同一個請求在加上這個選項前後實測: ```text remote_ip=127.0.0.1 # before remote_ip=16.162.199.171 # after: the client that started the request ``` 依用戶端的速率限制與 `client_ip` 匹配器,也是靠這個設定才能在 tunnel 後方看見真正的用戶端。它在啟動時讀取,所以變更後需要重啟,而不是重載([重載意味著什麼](/zh-TW/start/service/#-重載意味著什麼))。 `client_ip` 與 `{client_ip}` 使用所列標頭中的用戶端;`remote_ip` 與 `{remote_host}` 仍是 connector 的位址。只有受信任的對端能提供這些標頭。`CF-Connecting-IP` 必須明確列入 `client_ip_headers`。 ## ⚠️ 無法運作時 - **`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`,如上所述。 - **主機名稱無法解析。** 這筆記錄必須是指向 `.cfargotunnel.com` 且開啟代理的 CNAME;灰色雲朵的記錄會完全繞過 tunnel。 - **connector token 外洩了。** 輪替 tunnel 的 token,並用新的 token 重新安裝服務。 ## 🧭 下一步 - [提供靜態網站](/zh-TW/guides/static-site/):這些範例指向的源站。 - [TLS:可以調整什麼](/zh-TW/guides/tls-tuning/):當邊緣不終結 TLS 時,源站能用憑證做什麼。 - [以服務方式執行](/zh-TW/start/service/):源站上的 unit,以及 `trusted_proxies` 那段提到的重載語意。