Cloudflare 重定向次數過多怎麼辦:SSL 模式選錯導致的迴圈與修復

部落格 / 邊緣與 CDN

Cloudflare 重定向次數過多怎麼辦:SSL 模式選錯導致的迴圈與修復

站點剛接入 Cloudflare,瀏覽器就報“重定向次數過多”(ERR_TOO_MANY_REDIRECTS),最常見的原因是 SSL/TLS 加密模式設成了 Flexible,而源站自己又在把 HTTP 跳到 HTTPS。臨時的修法是把模式改成 Full;長期應該給源站裝上證書,改用 Full (strict)。如果改了模式還在迴圈,就用下面的 curl 命令看清 Location 鏈,看是哪一跳在兜圈子。

Flexible、Full、Full (strict) 到底差在哪?

Cloudflare 代理(橙色雲朵)開啟後,一次訪問分成兩段連線:瀏覽器到 Cloudflare 邊緣,邊緣到你的源站。SSL 模式只管第二段怎麼走。

瀏覽器 ──(1)──> Cloudflare 邊緣 ──(2)──> 源站
模式第 (2) 段協議是否校驗源站證書適用情況
OffHTTP不涉及不建議使用
Flexible始終 HTTP(80 埠)不涉及源站完全沒有 HTTPS 時的過渡
Full跟隨訪客協議,訪客走 HTTPS 時用 HTTPS(443)不校驗,自簽名或過期證書也能通源站有證書但還不合規時的過渡
Full (strict)同 Full校驗:證書須由公共 CA 或 Cloudflare Origin CA 簽發、未過期、域名匹配推薦的長期配置

較新接入的域名可能預設是“自動”模式,Cloudflare 會探測源站能力後替你選。具體選項名稱以控制檯 SSL/TLS → Overview 頁面為準。

為什麼 Flexible 會造成無限重定向?

把上表的 Flexible 那一行代入請求路徑,迴圈就清楚了:

  1. 瀏覽器請求 https://example.com/,第 (1) 段是 HTTPS。
  2. Flexible 模式下,Cloudflare 用 HTTP 去請求源站 http://example.com/。
  3. 源站的 Nginx 或應用配置了“HTTP 一律 301 到 HTTPS”,於是回一個 Location: https://example.com/。
  4. Cloudflare 把這個 301 原樣交給瀏覽器,瀏覽器再請求 https://example.com/,回到第 1 步。

源站看到的永遠是 HTTP,所以它會一直跳;瀏覽器看到的永遠是 HTTPS,所以它會一直跟。Chrome 和 Firefox 預設在跟了 20 次左右後放棄,報出這個錯誤。

同樣的結構還會以別的形式出現:源站把 HTTPS 跳回 HTTP,而 Cloudflare 又開著 Always Use HTTPS;或者重定向規則讓 www 跳到裸域,源站又讓裸域跳回 www。共同點是兩個環節對“正確的地址”意見不一致。

第一步:用 curl 看清 Location 鏈

瀏覽器會快取 301,排查時先別用它,直接用 curl。下面的命令跟隨跳轉,只列印每一跳的狀態碼和關鍵頭(-S 讓 curl 在靜默模式下仍輸出錯誤資訊):

curl -sSIL --max-redirs 8 https://example.com/ \
  | grep -iE '^(HTTP/|location:|server:|cf-cache-status:|x-powered-by:)'

一段典型的 Flexible 迴圈輸出長這樣(示例):

HTTP/2 301
server: cloudflare
location: https://example.com/
x-powered-by: PHP/8.x
HTTP/2 301
server: cloudflare
location: https://example.com/
...
curl: (47) Maximum (8) redirects followed

怎麼讀:

  • Location 指向自己:請求 https://example.com/ 卻被要求跳到 https://example.com/,基本可以斷定是協議不一致,優先查 SSL 模式。
  • 兩個地址來回切換(www 和裸域,或 http 和 https):是兩條規則互相打架,下面第三節逐個查。
  • 跳轉出自誰:經過 Cloudflare 的響應 server 頭都顯示 cloudflare,不能靠它區分。如果同時帶著源站才有的頭(如 x-powered-by、應用自定義頭),說明 301 是源站發的;只有 Cloudflare 的頭而沒有源站痕跡,多半是 Always Use HTTPS、Redirect Rules 或 Page Rules 發的。
  • cf-cache-status: HIT:301 被邊緣快取了,改完配置要去 Caching → Configuration 清快取,否則看起來“沒生效”。快取規則可以參考 Cache-Control 快取頭怎麼配。

第二步:繞過 Cloudflare 直接問源站

用 --resolve 把域名指到源站 IP,就能看到源站在 HTTP 和 HTTPS 兩種情況下各自怎麼回應。把 203.0.113.10 換成你的源站地址:

# 模擬 Flexible:Cloudflare 用 HTTP 回源
curl -sI --resolve example.com:80:203.0.113.10 http://example.com/

# 模擬 Full:Cloudflare 用 HTTPS 回源(-k 忽略證書,只看跳轉)
curl -skI --resolve example.com:443:203.0.113.10 https://example.com/

# 檢查源站證書能否透過 Full (strict) 的校驗(去掉 -k)
curl -sI --resolve example.com:443:203.0.113.10 https://example.com/

判斷方法:

第一條結果第二條結果結論
301 到 https200源站有 HTTPS,改成 Full 或 Full (strict) 即可
301 到 https連線失敗源站 443 沒監聽,先裝證書,或臨時關掉源站的強制跳轉
200301 到 http源站把 HTTPS 往回跳,配合 Always Use HTTPS 會迴圈,去掉源站這條規則
200200源站沒問題,去查 Cloudflare 側的規則

第三條命令如果報證書錯誤,說明源站證書不是公共 CA 簽發的,或已過期、域名不匹配,這時開 Full (strict) 會得到 526 錯誤,需要先換證書。例外是 Cloudflare Origin CA 證書:它不被 curl 預設信任,第三條命令同樣會報錯,要用 --cacert 指定 Cloudflare 官方文件提供的 Origin CA 根證書再測(見後文)。Cloudflare 邊緣返回的其他 5xx,例如 502、524,可以對照 大模型 API 錯誤碼速查。

如果 --resolve 不確定該填哪個 IP,或懷疑本地解析被改過,先按 DNS 汙染和 DNS 劫持的判斷方法 確認解析結果。

第三步:五個常見成因逐項檢查

1. SSL 模式是 Flexible,源站又強制 HTTPS

最常見。控制檯 SSL/TLS → Overview 改成 Full,清快取,再跑一遍第一步的 curl。源站有有效證書就直接用 Full (strict)。

2. Always Use HTTPS 和源站的反向跳轉衝突

SSL/TLS → Edge Certificates 裡的 Always Use HTTPS 會在邊緣把 HTTP 請求 301 到 HTTPS。如果源站有一條“HTTPS 跳 HTTP”的舊規則(常見於早年為了省證書寫的配置),兩邊會來回推。刪掉源站那條規則。

3. 源站自己的 301 判斷依據不對

Nginx 裡常見的寫法是在 80 埠的 server 塊裡 return 301 https://$host$request_uri;。這在 Full 模式下沒問題,因為 HTTPS 訪客對應的回源請求走 443。但如果源站前面還有一層反向代理,按 $scheme 判斷協議就會出錯。經過 Cloudflare 的請求會帶 X-Forwarded-Proto 和 CF-Visitor: {"scheme":"https"},應用層應讀這兩個頭來判斷訪客協議,或者乾脆讓 Cloudflare 負責跳轉,源站不再跳。

4. WordPress 的 siteurl 和 home

WordPress 會把請求跳到資料庫裡登記的地址。Flexible 模式下它收到的是 HTTP 請求,is_ssl() 返回 false,於是不斷把使用者送回 HTTPS。先查當前值(需要伺服器上裝有 WP-CLI):

wp option get siteurl
wp option get home

兩者都應該是 https:// 開頭,並且與你實際使用的主機名(帶不帶 www)一致。最省事的修法仍然是切到 Full (strict),讓 WordPress 真正收到 HTTPS 請求。如果暫時做不到,可以在 wp-config.php 裡 require_once ABSPATH . 'wp-settings.php'; 之前加上:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

這只是過渡辦法,源站依舊是明文回源。

5. www 與非 www 規則互相指向

例如 Cloudflare 的 Redirect Rules 把 www.example.com 跳到 example.com,而 Nginx 的 server_name 配置或 CMS 的站點地址又把裸域跳回 www。curl 輸出裡兩個主機名交替出現就是這種情況。只保留一處負責規範主機名,建議放在 Cloudflare 規則裡,源站只管返回內容。

為什麼長期應該用 Full (strict)?

Flexible 只加密了瀏覽器到邊緣這一段,邊緣到源站仍是明文,訪客的表單、Cookie 在這一段可以被沿途網路看到,而瀏覽器位址列顯示的是鎖。Full 加密了第二段,但不校驗證書,中間人用任意自簽名證書都能冒充源站。Full (strict) 兩段都加密,並確認對端確實是你的伺服器。

另一個實際好處是排障簡單:協議在兩段上一致,源站看到的 scheme 就是訪客的 scheme,前面第 3、4 條那類問題基本不會再出現。

怎麼簽發 Cloudflare Origin CA 證書並在 Nginx 配置?

Origin CA 證書免費,只被 Cloudflare 信任,專門用於邊緣到源站這一段。步驟如下:

  1. 控制檯進入 SSL/TLS → Origin Server,點 Create Certificate。
  2. 選擇由 Cloudflare 生成私鑰,金鑰型別 RSA 或 ECC 均可;主機名填 example.com 和 *.example.com;有效期按需選擇(最長可達 15 年,具體選項以控制檯為準)。
  3. 生成後頁面會顯示證書和私鑰。私鑰只顯示這一次,立即儲存到源站:
sudo mkdir -p /etc/ssl/cloudflare
sudo nano /etc/ssl/cloudflare/example.com.pem   # 貼上證書
sudo nano /etc/ssl/cloudflare/example.com.key   # 貼上私鑰
sudo chmod 600 /etc/ssl/cloudflare/example.com.key
  1. Nginx 配置:
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    http2 on;
    server_name example.com www.example.com;

    ssl_certificate     /etc/ssl/cloudflare/example.com.pem;
    ssl_certificate_key /etc/ssl/cloudflare/example.com.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
}

較舊版本的 Nginx 不支援單獨的 http2 on;,改成 listen 443 ssl http2;。

  1. sudo nginx -t && sudo systemctl reload nginx,然後回控制檯把模式改成 Full (strict)。
  2. 再跑一遍第一步的 curl:請求 https:// 地址應直接 200;請求 http:// 地址應只有一次 301 到 HTTPS,然後 200。
  3. 要從本機驗證源站證書,從 Cloudflare 官方文件下載 Origin CA 根證書(RSA 或 ECC,與第 2 步的金鑰型別對應),用它代替系統信任庫:
curl -sI --cacert origin_ca_rsa_root.pem \
  --resolve example.com:443:203.0.113.10 https://example.com/

兩點注意:Origin CA 證書不被瀏覽器信任,一旦把 DNS 記錄切到灰色雲朵(僅 DNS),訪客會直接看到證書錯誤;如果還想限制只有 Cloudflare 能連源站,可以在此基礎上開啟 Authenticated Origin Pulls,或在防火牆只放行 Cloudflare 公佈的 IP 段。回源保護的其他做法見 用 Cloudflare 加速 AI 應用:快取、API 限速與回源保護怎麼配。

修完之後的檢查表

  • SSL/TLS 模式為 Full (strict)
  • curl -sIL https://example.com/ 沒有跳轉或最多一跳,最終 200
  • curl -sIL http://www.example.com/ 跳到規範地址後 200,沒有來回
  • 直連源站 443 校驗證書透過(公共 CA 證書直接去掉 -k;Origin CA 證書用 --cacert 指定根證書)
  • 改配置後清過 Cloudflare 快取,瀏覽器用無痕視窗複測
  • 源站只有一處負責 HTTPS 跳轉,只有一處負責主機名規範化

如果配置都對,訪問仍然時好時壞,問題可能不在你這邊。cdnping 的 API 狀態頁 每 15 分鐘同步一次 Cloudflare 官方狀態頁,可以順手看看當時有沒有區域性事件;想比較各家公共 CDN 在國內的連線表現,可以看 CDN 速度榜 和 國內怎麼選公共 CDN。更完整的本地網路排查順序在 開發者網路自檢清單(2026 版)。需要基於 Cloudflare 網路做邊緣加速的團隊,可以看 cdnping Edge 的介紹;中國大陸境內加速需要 ICP 備案,並經由持證服務商。

相關文章

繼續閱讀