實測環境與硬體規格
| 項目 | 實際測試配置 |
| 測試日期 | 2026-10-02 |
| 作業系統 | Ubuntu 24.04.5 LTS |
| 主機數量 | 1 台新建隔離 VM;下列資源為每台配置 |
| CPU | 2 vCPU |
| 記憶體 | 4 GiB |
| 系統磁碟 | 32 GiB;HDD 儲存、VirtIO、ext4 |
| Linux 核心 | 6.8.0-139-generic |
| Caddy | 2.6.2 |
| cloudflared | cloudflared version 2026.9.3 (built 2026-09-24-16:07 UTC) |
用暫時 Cloudflare Tunnel 接到本機 Caddy,再轉發到 loopback 測試網頁;實測外部 HTTPS、真實來源 IP 與偽造標頭拒絕,完成後關閉入口。
文章目錄
本文以全新 Ubuntu 24.04 隔離主機和合成資料實測。套件來自經過簽章驗證、符合 Noble 的套件來源;沒有使用正式資料庫或正式網站的帳號。讀者請依自己的環境確認來源與版本。
圖中是測試主機實際 bash PTY 的執行紀錄,由瀏覽器呈現;提示符統一為 lab$,執行結果未改寫。文字命令另行保留,方便複製。
一、此次實測架構
外部瀏覽器
→ Cloudflare HTTPS 邊緣
→ cloudflared 建立的暫時 Tunnel
→ Caddy 127.0.0.1:8080
→ Python 範例網站 127.0.0.1:8081
這次三個程式在同一台新建隔離 VM,以 loopback listener 避免內網其他主機直接偽造來源標頭。對外只回傳「連線成功」與通用教學文字,不提供管理登入、檔案瀏覽或來源 IP 查詢。公開入口在完成測試後已關閉。
本篇驗證的是免帳號、免網域設定的 Quick Tunnel。它供測試使用,沒有生產可用性承諾,且有並行請求與 SSE 等限制;正式服務應用具名 Tunnel 與自己的網域。Quick Tunnel 文件
二、安裝受信任的原生套件
sudo apt update
sudo apt install caddy python3 curl ca-certificates gnupg
# 一般 Ubuntu 24.04 使用官方 Cloudflare Noble 來源的寫法
sudo install -d -m 0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \
| sudo gpg --dearmor --yes -o /usr/share/keyrings/cloudflare-main.gpg
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared noble main' \
| sudo tee /etc/apt/sources.list.d/cloudflared.list >/dev/null
sudo apt update
sudo apt install cloudflared
caddy version
cloudflared --version
本次受控環境由鏡像主機驗證 Cloudflare 目前有效簽章,再核對 Packages 與 deb 的完整 SHA-256 鏈,以自己的簽章發布給測試 VM。一般官方來源寫法如上;有套件鏡像政策的環境應沿用已核准的來源,不另行繞過。沒有下載或使用正式網站的 Tunnel token。官方套件來源
三、建立最小、只綁 loopback 的後端
以下範例示意與實測相同的後端處理方式。它把來源欄位存到私有檔案,對外完全不回傳這些值;目錄交給專用非登入帳號,日誌權限 0600。
sudo useradd --system --home /var/lib/demo-tunnel --shell /usr/sbin/nologin demo_tunnel
sudo install -d -o demo_tunnel -g demo_tunnel -m 0700 /var/lib/demo-tunnel
sudo tee /usr/local/lib/demo-tunnel-backend.py >/dev/null <<'PY'
from http.server import BaseHTTPRequestHandler, HTTPServer
import ipaddress, json, os, pathlib
class Handler(BaseHTTPRequestHandler):
def log_message(self,*args):
pass
def do_GET(self):
client=self.headers.get('CF-Connecting-IP','')
try:
ipaddress.ip_address(client)
except ValueError:
self.send_error(403)
return
event={'path':self.path,'client':client,
'forwarded':self.headers.get('X-Forwarded-For',''),
'transport':self.client_address[0]}
log=pathlib.Path('/var/lib/demo-tunnel/events.jsonl')
with log.open('a') as f:
f.write(json.dumps(event)+'\n')
os.chmod(log,0o600)
body='<h1>連線成功</h1><p>Temporary isolated tutorial service</p>'.encode()
self.send_response(200)
self.send_header('Content-Type','text/html; charset=utf-8')
self.send_header('Content-Length',str(len(body)))
self.end_headers()
self.wfile.write(body)
HTTPServer(('127.0.0.1',8081),Handler).serve_forever()
PY
# /etc/systemd/system/demo-tunnel-backend.service
[Unit]
After=network.target
[Service]
User=demo_tunnel
Group=demo_tunnel
ExecStart=/usr/bin/python3 /usr/local/lib/demo-tunnel-backend.py
NoNewPrivileges=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/demo-tunnel
[Install]
WantedBy=multi-user.target
四、設定 Caddy:listener 和 Host matcher 是兩件事
# /etc/caddy/Caddyfile
:8080 {
bind 127.0.0.1
@edge header CF-Connecting-IP *
handle @edge {
reverse_proxy 127.0.0.1:8081 {
header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
}
}
handle {
respond "Missing trusted edge header" 403
}
}
實測找出一個容易忽略的問題:若站點寫成 http://127.0.0.1:8080,還會產生 127.0.0.1 的 Host matcher;Quick Tunnel 帶著暫時公開網域的 Host 進來時,可能不符合路由而得到空白回應。這裡以 :8080 接收該 listener 的 Host,再用 bind 127.0.0.1 限定網路綁定。不是開放 LAN listener。
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl daemon-reload
sudo systemctl enable --now demo-tunnel-backend caddy
sudo systemctl restart caddy
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:8080/
直接呼叫 Caddy 且沒有可信邊緣標頭時,預期是 403。此模型信任同機的 cloudflared 與管理者;不適合讓不受信任的本機工作共享 listener。若改成跨主機代理,必須另外限制來源及設定可信 proxy,不能原封不動相信任意傳入的 CF-Connecting-IP。
五、啟動暫時 Tunnel,再由外部 HTTPS 連入
cloudflared --no-autoupdate tunnel --url http://127.0.0.1:8080
cloudflared 會顯示本次產生的 HTTPS 入口。用外部瀏覽器打開後應看到「連線成功」。本篇不公開實際暫時入口;完成測試後停止程序,該入口即不再提供這個 origin。實測用 systemd 管理相同程序;若改用下面的 service,先停止互動程序。
# /etc/systemd/system/demo-cloudflared.service
[Unit]
After=network-online.target caddy.service demo-tunnel-backend.service
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/cloudflared --no-autoupdate tunnel --url http://127.0.0.1:8080
Restart=no
StandardOutput=append:/var/log/demo-tunnel/cloudflared.log
StandardError=append:/var/log/demo-tunnel/cloudflared.log
[Install]
WantedBy=multi-user.target
command -v cloudflared
sudo install -d -m 0700 /var/log/demo-tunnel
sudo install -m 0600 /dev/null /var/log/demo-tunnel/cloudflared.log
sudo systemctl daemon-reload
sudo systemctl start demo-cloudflared
systemctl is-active caddy demo-cloudflared demo-tunnel-backend
本次官方 deb 的執行檔位於 /usr/local/bin/cloudflared;以 command -v 核對你的實際路徑再設定 ExecStart。此 unit 是短期教學配置,沒有自動重試,也沒有啟用開機對外入口。日誌權限 0600,僅私有管理使用。

六、驗證真正的使用者 IP,而不公開 IP
後端的 TCP transport peer 是 127.0.0.1,不能把它當成使用者 IP;正確來源要從可信 Tunnel 路徑帶入的 CF-Connecting-IP 取得。本次檢查器先在呼叫端觀察自己的 IPv4 出口,再向暫時 HTTPS 入口提出不同的測試請求,以私有日誌核對下列條件:
| 條件 | 實測結果 |
| CF-Connecting-IP 等於呼叫端出口 IP | 通過 |
| X-Forwarded-For 等於同一個使用者 IP | 通過 |
| 後端 transport peer 是 loopback | 通過 |
| 單獨偽造 X-Forwarded-For | 覆寫後仍是真正使用者 IP |
| 偽造保留的 CF-Connecting-IP 標頭 | 入口回傳 403,後端沒有該請求 |
| 缺少邊緣標頭的直接 Caddy 請求 | 403 拒絕 |

截圖只呈現比較是否一致,不呈現真正 IP、入口或原始日誌。檢查器確實送出三組外部請求,包含單獨偽造 XFF 與偽造保留 CF 標頭。前者核對真實 IP,後者核對 403 與後端沒有請求,才列出 PASS;畫面不是人工填入的預期結果。
七、正式自訂網域怎麼辦
可以使用自己在 Cloudflare 管理的網域,但 Quick Tunnel 的暫時名稱不能直接改成自訂名稱。正式入口要建立具名 Tunnel、設定 Public Hostname/DNS 路由,再用最小權限保存 connector 憑證。這次沒有建立新正式網域、沒有公開 Tunnel UUID 或 token,也沒有修改既有網站的 Tunnel。Cloudflare Tunnel 建置文件
八、完成測試就關閉暫時入口
sudo systemctl stop demo-cloudflared demo-tunnel-backend caddy
systemctl is-active demo-cloudflared
互動啟動者使用 Ctrl+C 停止 cloudflared;以本篇測試 service 執行者使用上述停止方式。實測已確認程序停止,重新向暫時入口的全新路徑請求也不再取得原本的「連線成功」。保留私有測試記錄在隔離主機,不放到 WordPress 媒體庫。
這次驗證了什麼
| 驗證項目 | 結果 |
| 外部 HTTPS 確實取得範例頁面 | 通過 |
| Caddy 與後端只綁 loopback | 通過 |
| 來源 IP 與呼叫端出口 IP 相同 | 通過 |
| 外部偽造來源標頭未被採信 | 通過 |
| 缺少可信標頭的直接請求 403 | 通過 |
| 停止後暫時入口不再提供原頁面 | 通過 |
實測範圍:實測 Quick Tunnel、同機 loopback Caddy/後端、真實 IP 相等與偽造標頭,以及入口關閉。未宣稱驗證新具名 Tunnel、自訂網域建置、跨主機 proxy 信任或正式容量/SLA。