Wordpress

WordPress 出現 loopback 錯誤?為什麼會發生,怎麼精準修好

外掛卡在安裝過程動彈不得、預約好的文章時間到了卻沒有發布、WooCommerce 的訂單通知信慢了半拍,這幾件事看起來毫不相干,多數人第一時間也不會往同一個方向想。事實上,它們常常是同一個原因造成的,那就是網站的 loopback 錯誤,也就是伺服器連不到自己。

這組機制平常安靜地運作,一旦出了狀況,前台看起來卻完全正常。訪客照樣打得開網站、逛得到商品頁,不會有任何畫面告訴他背後出了問題。多數人第一次注意到,是在後台的 Site Health(網站健康)頁面看到一句籠統的警示,搜尋這句話找到的排除文章又常常先叫你去改 wp-config.php,結果真正的問題其實藏在另一層設定。

loopback 錯誤是什麼?網站自我請求失敗的警訊

WordPress 官方的進階管理手冊把 loopback 定義得很直白,就是網站或伺服器自己嘗試連到自己。技術上,這條路徑靠 wp_remote_post()wp_remote_get() 這套 HTTP API 呼叫自己網站的網址,而不是對外部服務發請求。它的用途集中在 3 件事:觸發排程發文與外掛的背景工作、外掛與佈景主題編輯器存檔時回頭連自己網站驗證程式碼不會讓網站掛掉,以及 Site Health 部分檢查項目本身。這不是什麼冷門的邊角功能,而是 WordPress 背景運作的骨架之一。

真正麻煩的地方在於,這整組請求完全不會經過瀏覽器。訪客瀏覽網站、下單結帳,都不會觸發 loopback,前台自然一切正常。問題卻在看不到的地方安靜地拖著:外掛裝到一半停滯不前、排程好要發布的文章時間到了卻沒有上線、WooCommerce 的訂單通知信慢了半拍、備份或資安掃描默默逾時失敗。前台正常不等於沒事。

loopback 是網站用 wp_remote_post() 對自己網址發出的內部請求,不經過瀏覽器,前台照常但背景排程可能默默失敗
loopback 是網站繞回自己的內部請求,訪客走的前台一切正常,卻看不出背景排程其實已經停擺。

loopback 請求失敗的常見成因

loopback 失敗不是單一原因,而是有 2 種性質完全不同的問題混在一起:一種是網路層,CDN、主機防火牆、資安模組把這個請求擋在半路;另一種是應用層,Basic Auth、SSL、逾時、PHP session 這類設定讓請求連得到,卻在驗證這一關被拒絕。分清楚自己碰到的是哪一種,才不會對症下錯藥,最常見的誤判,就是看到 loopback 失敗就先跑去改 wp-config.php,結果問題其實出在 CDN 那一層。

CDN 與主機防火牆先擋下了自己的請求

這是最常見、也最典型的情境。網站掛在 Cloudflare 或其他 CDN/WAF 後面時,DNS 記錄通常設成代理模式,也就是俗稱的橘雲。所有對外的流量都要先經過 Cloudflare 的邊緣節點,再轉發到真正的主機。Cloudflare 官方文件說明得很清楚,這正是保護來源伺服器的機制,代理模式會隱藏來源 IP,任何連到這個網域的請求,包括網站自己發出的請求,都得先過這一關。loopback 要透過 DNS 解析回自己的公開網域,等於重新繞了一圈,經過自己前面的防護層,被當成一般外部流量重新過一次 Managed Rules 檢查。

問題出在這個請求跟真人瀏覽器長得完全不一樣。它沒有瀏覽器指紋,User-Agent 是 WordPress 內部字串,不是常見的瀏覽器 UA,而且短時間內固定對同一個路徑重複發出,像是 /wp-cron.php/wp-json/...。Cloudflare 官方文件提到,IP 存取規則有一個常見用途,就是放行定期存取網站的服務,例如 API、爬蟲程式與金流商。反過來說,凡是這類非典型瀏覽器的自動化請求,正是最容易被機器人防護或速率限制判定為可疑而擋下的對象。回應變成連線被拒或直接逾時,結果就是網站對外部世界暢通無阻,卻連不到自己的網域,因為自己的網域也要繞經 CDN 這一層。這是網路層的問題,不是 WordPress 本身的設定寫錯。

Basic Auth 讓網站認不出自己

這種情況常見於測試站、staging 環境,或是主機商預設就在後台加了一層 HTTP Basic Auth 密碼保護。WordPress 核心其實有嘗試處理這個情境,WP_Site_Health::can_perform_loopback() 這支函式會檢查當下這次連線的 PHP_AUTH_USERPHP_AUTH_PW 是否存在,如果存在,核心就會自動組成一組 Authorization: Basic 標頭,一起夾帶進 loopback 請求裡。

只是這個自動處理有明確的前提,只有觸發檢查的那一次連線本身帶著 Basic Auth 資訊時才轉得過去。如果 Basic Auth 是獨立設定在伺服器層,例如寫在 .htaccess 裡,跟這次觸發檢查的連線無關,或者保護規則涵蓋的路徑跟 loopback 實際打的路徑對不上,這個內部請求依然會被要求輸入帳密而遭拒絕。典型的症狀,就是 loopback 測試回傳 HTTP 401 未授權。

SSL 憑證與逾時等技術面因素

SSL 憑證鏈不完整或用了自簽憑證,聽起來像是最直覺的原因,但實際影響往往沒有想像中大。loopback 做的是 HTTPS 呼叫,WordPress 對本地請求卻有一個可調整的 SSL 驗證開關 https_local_ssl_verify,預設值就是 false,也就是預設不驗證本地請求的憑證。真正常見的反而是主機環境對 TLS 版本或加密套件設定不一致,導致連線在交握階段就失敗。

逾時是另一個容易被忽略的因素。Site Health 這個 loopback 測試給的時間很短,核心程式碼把逾時寫死為 10 秒,主機資源吃緊,或是首次觸發較慢的外掛,例如大型快取預熱,很容易在時間內沒收到回應而被判定失敗。

WordPress 官方文件還特別點名一個容易被忽略的情境,也就是外掛呼叫了 session_start() 卻沒有在發出 HTTP 請求前呼叫 session_write_close()。PHP session 鎖定會直接干擾 REST API 與 loopback 請求,這個問題經常出現在寫得不夠嚴謹的外掛或客製功能裡,排查時也值得列入清單。

主機安全模組把自己的請求誤判成攻擊

部分主機,尤其是共享主機或 cPanel/DirectAdmin 環境,會在伺服器層另外掛一套資安模組,跟掛在網站前面的 CDN WAF 是不同的兩層,這一層裝在主機本身,連 CDN 都還沒經過就先被攔下。以 CloudLinux 旗下的 Imunify360 為例,官方文件本身就承認網站連不到自己是已知情境,外掛面板出現「Your site can’t reach itself」警示時,代表排程任務,包括自動的機器人資料更新,可能無法執行。

官方建議的處理方式是先排除本地 DNS 或防火牆問題,再按面板上的 Re-check 重新驗證,而不是直接停用整個防護模組。這一點值得記住,主機層的資安模組要去主機控制台處理,跟 CDN 那一層要分開排查,別搞混去哪裡改設定,否則常常會白忙一場改錯地方。

WP_HTTP_BLOCK_EXTERNAL 預設其實不擋自己

不少故障排除文章一看到 loopback 失敗,第一步就是叫讀者去 wp-config.php 檢查有沒有設定 WP_HTTP_BLOCK_EXTERNAL。這其實是一個常見的誤會。

讀 WordPress 核心 WP_Http::block_request() 的原始碼會發現,這個常數的設計目的是封鎖對外部主機的請求。啟用之後,只有 localhost 與網站自己的網址能發出 HTTP 請求,其他外部網址都會被擋下,除非另外寫進 WP_ACCESSIBLE_HOSTS 的允許清單。程式邏輯裡明確判斷,只要目標網址的 host 是 localhost,或跟自己網站的 host 相同,就會回傳 apply_filters( 'block_local_requests', false ),而這個過濾器的預設值就是 false,也就是不封鎖。核心的註解也寫得很直接,說預設不封鎖回頭連自己的請求。

換句話說,如果真的是 loopback 連不上,十之八九不是這個常數造成的,除非還額外掛了 block_local_requests 這個過濾器主動關掉。花時間去改這個常數,多半只是白工,真正該查的是前面 4 種情況。

自己動手驗證,別只看 Site Health 那句警示

Site Health 只給一句籠統的「網站無法完成迴圈要求」,加一行 cURL 錯誤代碼,不會告訴你卡在網路層還是應用層。與其對著這句話猜原因,不如直接從主機端動手重現,把猜測換成證據。

用 curl 對 wp-cron.php 重現 loopback 自我測試,連線被拒或逾時代表卡在網路層,收到 401 或 403 則是應用層
用 curl 重現自我測試,連不上是網路層問題,連得上卻被拒絕才是應用層。

curl 能重現 WordPress 內建的自我測試

WordPress 核心實際在做的測試,就是對自己網站的 wp-cron.php 發一個 POST 請求,帶上 site-health=loopback-test 這個參數。你可以在主機的 SSH 端,用 curl 手動重現同一個請求:

curl -X POST "https://你的網域/wp-cron.php" -d "site-health=loopback-test" -m 10 -k -vCode language: Bash (bash)

這幾個參數不是隨便挑的,每一個都對應核心邏輯的一部分:-m 10 對應核心寫死的 10 秒逾時、-k 對應核心預設不驗證本地 SSL、-v 印出完整的交握過程,方便判斷是連線層失敗,還是連得上卻在應用層被拒絕。

看到的結果如果是連線逾時或連線被拒絕,通常代表卡在網路層,例如防火牆、WAF 或 DNS 設定;如果連得上,卻收到 401 或 403 這類回應碼,才是應用層的問題,例如 Basic Auth 或資安規則主動擋下。這個判斷邏輯直接決定接下來該往哪個方向查,不必兩邊都試一輪。

WP-CLI 一行指令驗證排程是否正常執行

如果主機有 SSH 又裝了 WP-CLI,比手動 curl 更快的做法是直接跑官方指令:

wp cron testCode language: Bash (bash)

這支指令會依序做 3 件事:先檢查是否設了 DISABLE_WP_CRON,設了就直接報錯,因為這代表 WP-Cron 本來就被人為關掉,根本不是 loopback 的問題;接著檢查是否設了 ALTERNATE_WP_CRON,設了會顯示警告;最後才真正嘗試透過 HTTP 觸發一次 WP-Cron,收到非 200 的回應碼就會警告。全部通過時,會印出固定字串 Success: WP-Cron spawning is working as expected.

這支指令的價值,在於它會先排除其實是被人為關掉這個假訊號,才真正進到網路層的測試。少了這一步,很容易白忙一場去排查防火牆規則,查了半天才發現只是自己在 wp-config.php 設了 DISABLE_WP_CRON 忘記拿掉。

從錯誤代碼分辨卡在網路層還是應用層

測完前面 2 個小節,手上通常已經有一串錯誤訊息。把常見的錯誤代碼整理成對照,能省下不少一個個查文件的時間:

錯誤代碼代表的意思通常該查哪一層
cURL error 7連線被拒絕(Failed to connect)主機防火牆或網路層直接拒絕
cURL error 28連線逾時(Operation timed out)封包送出去了卻沒收到回應,常見於 WAF 挑戰流程或主機資源逾時
HTTP 401未授權連得上,但被 Basic Auth 擋下
HTTP 403禁止存取連得上,但被 WAF 或資安規則明確拒絕,最常見於 CDN 或主機資安模組

這張表是這一節的核心產出。前面 2 個小節測出來的結果,對照這張表就能決定下一步該往哪個方向修,不必兩層都排查一遍。

精準放行,不必整組關掉安全防護

找到卡在網路層之後,正確的做法是只放行這一條路徑、這一個來源,而不是圖方便整組關掉 WAF 或防火牆,那樣等於把安全性一起賠掉。精準放行優於全面關閉,CDN 層、主機層、應用層各自的鎖法不太一樣。

精準放行只鎖定 wp-cron.php、wp-json 路徑與主機來源 IP 並設為 Skip,不必對整個網域關掉 WAF 或防火牆
精準放行只開放 loopback 這條路徑與來源,其餘安全防護照常,不必整組關掉。

Cloudflare WAF 規則要鎖路徑與來源 IP

在 Cloudflare 建立自訂規則(Custom Rules)時,同時鎖定兩個條件:目標路徑限定在 /wp-cron.php/wp-json/* 這類會發生 loopback 的路徑,來源限定在主機自己的伺服器 IP,動作設為 Skip(略過安全檢查)。不要對整個網域關掉 WAF,也不要把伺服器 IP 全域列入允許清單,那樣等於伺服器一旦被入侵,也不會被自家 WAF 攔下,反而失去了原本設防護的意義。

Cloudflare 官方文件本身也建議同樣的方向,升級到自訂規則時建議用 Skip 動作取代舊版 IP Access Rules 的 Allow 動作,因為 Skip 不會略過所有的安全機制。官方文件對 IP 存取規則的用途定位也很清楚,放行定期存取網站的服務,例如 API、爬蟲程式與金流商,而 loopback 請求正好就是這種固定來源、固定路徑的自動化流量,用 Skip 精準放行是最貼近官方建議的做法。

主機防火牆和資安模組的調整方式

cPanel/DirectAdmin 類主機常見用 CSF(ConfigServer Security & Firewall)這套防火牆。背後的公司 Way to the Web 已於 2025 年 8 月 31 日正式結束營運,CSF 停止官方支援與銷售,但結束前釋出的最終版本已轉為開源,採用 GPLv3 授權。cPanel 官方隨後宣布,自 2026 年 2 月 25 日起發布並維護一個聚焦安全性與穩定性修補的公開 fork,符合條件的 cPanel/WHM 伺服器會自動改指向 cPanel 的更新來源。如果主機還在用 CSF 或它的 fork,重點是找到連線追蹤排除本地/自我連線這類設定項,只排除本機的自我連線,不要整組關閉連線追蹤或整個防火牆。

用 Imunify360(CloudLinux)的主機則不太一樣,後台面板本身就有針對這個情境的檢測與說明,官方建議的做法是先排除本地 DNS 或防火牆問題,再按面板的 Re-check 重新驗證。這 2 種情境有一個共同的提醒,這一層通常要透過主機控制台操作,改不動就直接聯絡主機商,講清楚 Site Health 顯示 loopback 失敗、需要放行主機對自己網域的請求這句具體描述,而不是籠統說一句網站壞了,描述得越具體,主機商客服才越快抓到問題在哪。

Basic Auth、SSL 各自的排查修法

Basic Auth 造成的問題,排查期間可以先暫時移除或調整 .htaccess 裡的 Basic Auth 規則,處理完再視需要恢復。同時要留意前面提過的限制,WordPress 核心自動帶入 Basic Auth 帳密這件事,只在觸發檢查那個當下的連線本身帶有 Basic Auth 時才有效,真正排程性質的 loopback 呼叫,例如背景自動觸發的 wp-cron,並不會有這組資訊。這也是為什麼 Basic Auth 保護的環境常出現一種落差,手動點 Re-check 顯示正常,但排程實際上還是沒有真的跑。

SSL 或逾時類問題,先用前一節的 curl -v 確認是連線逾時,還是憑證交握失敗。這裡有一個常被搞混的地方:Site Health 那個寫死 10 秒的測試,跟 WordPress 實際觸發 wp-cron 背景工作的請求並不是同一組逾時設定。核心把 wp-cron 背景觸發做成一個逾時僅 0.01 秒的非阻塞請求,送出去就不等回應,並不會因為主機處理較慢而被判定失敗。真正會受主機資源緊繃影響、且可以透過 http_request_timeout 這個過濾器(預設 5 秒)調整逾時秒數的,是其他沒有另外指定逾時的一般 WordPress HTTP API 請求。至於 PHP session 鎖定,正確的處理方式是提醒外掛作者或負責客製功能的開發者,務必在發出 HTTP 請求前呼叫 session_write_close(),把鎖定釋放掉。

警示消失不代表排程真的恢復

改完防火牆規則,看到 Site Health 從紅字變綠字,很多人就以為結束了。但警示消失不等於背景功能真的恢復正常,排程有可能還是卡著。用官方指令直接看排程的下一次執行時間有沒有正常往前推進,比看 Site Health 那顆綠燈更直接。

用 wp cron event list 檢查排程時間戳

跑這行指令:

wp cron event listCode language: Bash (bash)

預設會列出 hooknext_run_gmtnext_run_relativerecurrence 這幾欄,內建排程如 wp_version_checkwp_update_pluginswp_update_themes 都會出現在清單裡。重點看 next_run_gmt 這一欄,如果這些時間戳長時間停在過去,沒有往前推進,代表排程實際上沒有真的被觸發,即使 Site Health 顯示綠燈也不能掉以輕心。正常狀況下,這些時間應該隨著每次排程執行持續往未來遞增。

需要做成簡易監控的話,可以搭配 --fields=hook,next_run --format=json 把結果轉成 JSON,方便寫進監控腳本裡定期比對。

CDN、快取設定異動後,養成回頭複查的習慣

loopback 失敗常常不是一次性事故,而是某次調整之後才冒出來的副作用。開啟 CDN 某個安全等級、調整快取規則、搬家換新主機、換了新的資安模組,都可能重新觸發同樣的問題,而且往往是無聲無息地重演,不會有任何通知跳出來告訴你排程又停擺了。

比較穩妥的做法,是把動了 CDN、WAF 或快取設定之後,回頭跑一次 wp cron test 或看一眼 Site Health 變成標準動作,而不是等到外掛裝不上、排程文章又沒發出去,才回頭追查。這個習慣花不了兩分鐘,卻能省下下一次從頭排查的時間。

loopback 錯誤真正麻煩的地方,從來不是這個功能本身多複雜,而是它安靜到讓人容易忽略——訪客照樣逛得到網站,問題卻在背景一路累積,等到外掛裝不上或訂單信慢了好幾天才被發現。找出問題的關鍵,是先分清楚問題落在網路層還是應用層,再用 curl 或 WP-CLI 這類工具重現證據,而不是對著 Site Health 那一句警示用猜的。

修法上,精準放行永遠優於整組關掉防護,鎖定路徑、鎖定來源 IP,把安全性跟排程功能兩件事都處理好,才是真正解決問題,而不是拆掉一道牆去換一時的方便。等排程時間戳真的往前推進,這件事才算真正處理完。

常見問答

本區問答由 AI 依文章內容自動整理,僅供快速參考,正式內容仍以全文為準。

loopback 錯誤代表什麼問題?

loopback 錯誤代表網站或伺服器連不到自己,靠 wp_remote_post/wp_remote_get 呼叫自己的網址,用在觸發排程、外掛背景工作與存檔驗證,是 WordPress 背景運作的骨架之一,不是冷門功能。

掛 CDN 為什麼容易 loopback 失敗?

因為 DNS 設成代理模式後,連到這個網域的請求都要先過 CDN 邊緣節點,loopback 請求解析回自己網域,等於重新繞一圈被當成外部流量檢查,它又沒有瀏覽器指紋、對同一路徑重複發出,容易被防護判定可疑擋下。

wp-config.php 常是元凶嗎?

通常不是。常見誤解是去改 WP_HTTP_BLOCK_EXTERNAL 常數,但它只封鎖對外部主機的請求,只要目標 host 跟自己網站相同,核心預設就不封鎖,回頭連自己本來就放行,改這個常數多半是白工。

怎麼用 curl 判斷 loopback 卡在哪一層?

對自己網域的 wp-cron.php 發一個帶 loopback-test 參數的 POST 請求,加 -m 10 -k -v 重現測試。連線逾時或被拒絕通常卡網路層,例如防火牆;連得上卻收到 401 或 403,才是應用層問題。

Site Health 變綠燈就代表排程真的恢復了嗎?

不代表。警示消失只說明那次測試通過,背景功能不一定恢復。要用 wp cron event list 看排程清單的 next_run_gmt 一欄,若時間戳長時間停在過去沒往前推進,代表排程其實沒被真正觸發,綠燈也不能掉以輕心。

資料來源
  1. Loopback Requests — WordPress
  2. WP_Site_Health::can_perform_loopback() — WordPress
  3. Site Health Screen — WordPress
  4. IP Access rules — Cloudflare
  5. Protect your origin server — Cloudflare
  6. Troubleshooting managed rules — Cloudflare
  7. WordPress plugin — Imunify360
  8. WP_Http::block_request() — WordPress
  9. wp cron test — WordPress
  10. wp cron event list — WordPress
  11. http_request_timeout — WordPress
  12. cPanel will provide its own fork of CSF starting Feb 25th, 2026 — cPanel