如何找出 Nginx 502 Bad Gateway 的根本原因

HTTP 502 錯誤會讓服務瞬間受阻。使用者看到的是一個含糊的失敗頁面,而你的監控系統則會立刻亮起警報。殘酷的現實是:Nginx 只是傳話的人,真正的問題出在你的反向代理之後。
本指南提供一套逐步排查的方法,幫助你找出 Nginx 中 502 Bad Gateway 錯誤的根本原因。你將了解「我該如何一步步找到根本原因?」這個問題的答案:從代理錯誤日誌開始,然後逐層檢查上游服務、網路規則、Nginx 設定以及系統安全層。每一層都會進一步縮小排查範圍。
只要按照這個順序執行,你就能停止盲目猜測,真正修復每一次 502 背後的實際問題。
從代理錯誤日誌著手診斷 502 Bad Gateway
當你遇到 HTTP 502 錯誤時,第一步永遠應該是查看代理錯誤日誌。這些日誌會準確告訴你,為什麼反向代理回傳了 502。先不要急著查看應用程式,也不要立刻調整逾時設定。先看代理錯誤日誌。Nginx 在其中寫下的訊息,往往會直接指出根本原因。這樣做可以為你節省數小時的盲目排查時間。每一次 Nginx 中的 bad gateway 錯誤,都會從這些日誌裡留下線索。你不需要猜測錯誤是怎麼產生的,日誌會立刻給出答案。
定位 Nginx 錯誤日誌
你首先需要檢查 Nginx 錯誤日誌。預設路徑通常是 /var/log/nginx/error.log。許多發行版還會為單獨的 server block 使用 /var/log/nginx/your-site-error.log。要確認準確路徑,請檢查你的 Nginx 設定檔,查找 error_log 指令,路徑就緊跟在該指令之後。
找到檔案後,請即時查看日誌。可以使用指令 tail -f /var/log/nginx/error.log。在指令執行時重現 502 Bad Gateway 錯誤。錯誤發生時,新的日誌行會立即出現。你就能看到 Nginx 回傳該錯誤的準確時間點。
你還可以使用 grep 過濾特定訊息。執行 tail -f /var/log/nginx/error.log | grep upstream。這會只顯示包含 upstream 的日誌行。過濾後更容易聚焦與代理相關的錯誤。忽略與靜態檔案有關的無關項目,只關注包含 upstream 或 connect 的訊息。
辨識常見日誌訊息
打開錯誤日誌,重點觀察四種常見模式。每一種模式都對應著不同的上游問題。下面這張表列出了最常見的訊息、它們通常代表什麼,以及你的下一步操作:
| 日誌訊息 | 可能原因 | 下一步操作 |
|---|---|---|
connect() failed (111: Connection refused) | 應用已停止,或 proxy_pass 使用了錯誤連接埠 | 檢查服務監聽狀態和目前生效設定 |
upstream timed out | 應用過慢、資料庫過慢,或工作執行緒池耗盡 | 在提高逾時值之前,先追蹤延遲與資源壓力 |
upstream prematurely closed connection | 應用當機、連線被重設,或回應過程失敗 | 對照應用日誌與程序重新啟動時間進行關聯排查 |
no live upstreams | 上游池中的所有後端都不可用 | 檢查健康檢查、部署狀態和上游位址 |
最常見的錯誤訊息是 connect() failed (111: Connection refused)。這表示上游伺服器已宕機。應用程序可能已經當機,或者根本沒有啟動,也可能是代理指向了錯誤的連接埠。代理收到的是「連線被拒絕」,表示在該位址上沒有應用正在監聽。
第二種最常見的模式是 upstream prematurely closed connection。代理把請求發送給上游後,上游開始處理,但在完整回應返回之前就斷開了連線。這通常表示以下兩種情況之一:
- 上游伺服器可能因為逾時設定過短而主動斷開連線。這樣代理會在請求完成前收到 FIN 或 RST 封包。
- 上游應用可能在處理過程中當機。連接埠上不再有程序監聽,此時作業系統核心會向代理發送一個 RST 封包。
- 無論哪種情況,代理都會把這種過早關閉視為發給 Nginx 的無效回應,最終結果就是 502 Bad Gateway。
因此,當你看到這條訊息時,應立即檢查上游應用日誌。查看是否存在當機堆疊,或是否有逾時限制。應用本身會告訴你它為什麼斷開連線。
確認上游伺服器正在執行
後端當機或根本未啟動,是 502 Bad Gateway 最常見的原因。在查看完代理錯誤日誌後,下一步合乎邏輯的操作,就是確認上游應用是否真的在監聽請求。錯誤日誌已經告訴你是哪個上游位址連線失敗,現在你需要確認該位址背後的程序是否存活。僅這一步,就能解決大多數觸發該錯誤的 Nginx 事故。不要跳過。你的目標是在檢查其他層之前,先確保上游伺服器處於執行狀態。當 Nginx 從上游伺服器收到無效回應時,就會回傳你看到的錯誤碼。來自上游的無效回應或無回應,都會導致同樣的結果。理解這些日誌訊息,能幫助你把錯誤日誌和實際問題對應起來。
檢查服務狀態
大多數 Linux 發行版都使用 systemd 管理應用服務。你可以用一條指令檢查 PHP-FPM 或 Gunicorn 這類上游服務是否處於啟用狀態。在上游主機上打開終端機,執行以下通用狀態檢查指令:
systemctl status <service-name>—— 這是一個通用指令,可用於檢查任何由 systemd 管理的服務狀態,包括 Node.js、PHP-FPM 或 Gunicorn。
將 <service-name> 替換為你的實際服務名稱。對於 PHP 應用,具體指令通常會包含版本號:
sudo systemctl status php8.1-fpm—— 用於檢查 PHP-FPM 服務狀態。
輸出通常會顯示三種狀態之一:active、inactive 或 failed。如果你看到 active 且帶有 running 標記,表示服務還活著。如果看到 inactive 或 failed,就用 sudo systemctl start <service-name> 啟動服務。然後再次測試 502 是否消失。如果服務是 active,但錯誤仍然存在,就繼續看下一小節。錯誤日誌中也可能出現 upstream server is unavailable 之類的訊息,這通常發生在服務無法啟動時。
如果你使用 Node.js,可透過 ps aux | grep node 確認程序是否還在。同時也要檢查應用日誌。Node.js 應用常常會靜默當機,而不會通知程序管理器。一個已停止的 Node 程序,未必會在系統日誌中留下明顯錯誤。你必須查看它自己的日誌檔,才能知道退出原因。像 PM2 這樣的工具可以自動重新啟動程序,但根本原因仍然需要透過日誌來調查。
測試連接埠與連通性
服務正在執行,並不代表它一定監聽在你預期的連接埠上。應用可能啟動在了另一個介面或另一個連接埠,而不是你在 Nginx 中設定的那個。這種不匹配會導致 upstream server is unavailable 的情況。Nginx 嘗試連線,卻發現目標位址上沒有服務,於是將狀態記為 upstream server down,錯誤日誌也會記錄這一失敗。
可以在 Nginx 主機上使用 curl -v http://localhost:PORT 測試直連。將 PORT 替換為上游連接埠。若回應成功,表示應用確實有輸出;若出現 Connection refused,則可確認連接埠不匹配。此時應檢查應用實際綁定的連接埠,然後把 proxy_pass 指令改成正確值。你也可以使用 telnet 作為替代測試。執行 telnet <upstream-ip> <port>。連線成功時,通常會出現一個空白畫面並閃爍游標;如果失敗,則會顯示 Connection refused。
對於 Nginx Proxy Manager 使用者,即使在管理介面中看到的通訊協定和連接埠似乎都正確,502 仍然可能出現。此時應直接驗證上游容器或服務,例如在 Nginx 容器內部,或在執行 Nginx Proxy Manager 的主機上執行 curl。因為 Web 介面顯示的內容,並不總能反映執行階段的真實狀態。
如果 curl 成功,但 Nginx 仍然回傳 502 Bad Gateway,那麼問題可能出在逾時、緩衝區或其他層面。但如果 curl 失敗,你就已經確認上游伺服器不可達。先修復應用監聽問題,再繼續下一步。
排除防火牆和網路阻擋
防火牆規則或雲端安全群組可能會在 Nginx 與上游伺服器之間悄悄阻擋流量。應用本身執行正常,連接埠監聽也沒問題,但 Nginx 仍會回傳 502,因為某個封包過濾器丟棄了連線請求。這一層位於兩個都「看似健康」的服務之間,因此很容易被忽視。
檢查防火牆規則
先從列出 Nginx 主機上的活動規則開始。指令 iptables -L -n -v 會顯示所有鏈(包括 INPUT、OUTPUT 和 FORWARD)的規則及其匹配流量。你可以藉此驗證,發往特定上游連接埠的流量是否被允許。更簡潔的視圖是 iptables -L,它會列出預設表中的目前活動規則,讓你快速了解整個防火牆設定。
另外兩條指令也有助於你審查規則集:
sudo iptables -S—— 以可保存、可重用的格式顯示目前規則集。示例輸出通常會列出 INPUT、FORWARD 和 OUTPUT 鏈的預設策略(例如都為 ACCEPT),以及是否存在額外規則。sudo iptables -L—— 以更易讀的表格形式顯示規則。示例輸出會展示 INPUT、FORWARD 和 OUTPUT 鏈的預設策略,以及目前活動規則(例如允許 RELATED,ESTABLISHED 連線的 ACCEPT 規則)。
如果你的 Nginx 執行在雲端環境中,還要檢查該實例對應的安全群組或網路 ACL。這些控制位於主機之外,可能在 iptables 看到流量之前就已經把連線阻擋了。
使用 curl 和 telnet 測試
查看規則告訴你「理論上應該怎樣」,而測試才能說明「實際上發生了什麼」。在 Nginx 主機上執行 curl -v http://<upstream-ip>:<port>。如果能成功回應,表示網路路徑是通的;如果一直卡住或被拒絕,則表示要麼有阻擋,要麼監聽端已失效。
你還可以使用 telnet <upstream-ip> <port> 做第二次驗證。若出現空白畫面並伴隨閃爍游標,表示連線已打開;若被拒絕或逾時,則表明存在阻擋。如果這兩項測試都失敗,但服務在本機上執行正常,那麼防火牆規則或安全群組就是根本原因。修復規則後重新測試。一旦 Nginx 能重新連通上游,502 通常就會消失。
調整逾時與緩衝區大小
一個回應緩慢的上游,也可能觸發被 Nginx 記錄為 502 的逾時錯誤。代理已經在等待回應,但後端耗時太久,Nginx 最終放棄並回傳錯誤。你看到的是閘道失敗,真正的問題卻是延遲。這種情況通常發生在上游伺服器最終是能完成回應的,只是沒有在設定的時間視窗內完成。
調整 proxy_read_timeout 和 proxy_connect_timeout
有兩個指令控制 Nginx 等待的時長。proxy_connect_timeout 指令設定與上游建立連線的時間上限;proxy_read_timeout 指令定義 Nginx 在兩次讀取上游資料之間允許等待的最長時間。只要任一限制到期,Nginx 就會關閉連線並回傳 502。
這些值應根據應用的正常回應時間來設定。資料庫負載較重的頁面,可能需要更長的讀取逾時;而簡單的 API 介面,可能所需時間更短。每次修改後都應重新測試。需要注意的是,如果上游本身確實過慢,單純提高逾時只是掩蓋症狀,因此應先調查應用效能。
為大型回應標頭增大 proxy_buffer_size
過大的回應標頭同樣可能引發 502。Nginx 會為上游回應標頭分配緩衝區,預設大小通常為 4k 或 8k。當回應標頭超過這個限制時,Nginx 就無法正確處理該回應,並回傳錯誤。
根據原始說明,像 Laravel 這類會產生較長工作階段 Cookie 的應用、某些單一登入實作,以及回傳大量 Set-Cookie 標頭的系統,常常會超過預設的 4k 或 8k proxy_buffer_size,從而導致 502 錯誤。在這些情況下,需要將 proxy_buffer_size 調大,才能避免該錯誤。
當你識別出這種模式後,應把 proxy_buffer_size 調整為更大的值。同時,也可以一併考慮 proxy_buffers 和 proxy_busy_buffers_size 這兩個相關參數。修改之後繼續觀察錯誤日誌。一旦緩衝區足以容納完整回應標頭,這類與標頭相關的 502 通常就會消失。
確認 Nginx 設定中的上游位址
上游名稱或連接埠中的一個拼寫錯誤,都是非常常見的根本原因。你可能把 Nginx 指向了錯誤的位址。結果就是:即使應用本身執行良好,502 仍然持續存在。因此,在排查其他層之前,你必須仔細檢查 Nginx 設定。
檢查 proxy_pass 和 upstream 區塊
proxy_pass 指令告訴作為反向代理的 Nginx,應該把請求轉發到哪裡。如果你把它設定為一個不存在的主機名稱,或一個沒有服務監聽的連接埠,那麼問題就出在 Nginx 設定本身。打開你的 Nginx 設定檔,找到相關 location 區塊中的 proxy_pass 行,然後將其與上游應用的實際位址逐一比對。最常見的錯誤之一,就是連接埠或 socket 路徑寫錯。比如你的應用實際監聽 8080,但你卻寫成了 8081,這種不匹配就會導致 502。若你使用了 upstream 區塊,也要一併檢查。upstream 區塊定義的是一個伺服器群組,隨後 proxy_pass 會引用這個群組名稱。如果被引用的名稱拼寫錯誤,結果也一樣會導致 502。務必確認你使用的是正確的上游伺服器和連接埠。你還可以在主機上直接用 curl 測試,確認該位址確實可用。這個步驟能節省大量時間,避免不必要的排查。
確認 location 區塊順序
Nginx 會按照特定順序處理 location 區塊。它先匹配前綴 location,然後再按照書寫順序匹配正則 location。第一個匹配到的 location 區塊會處理請求。如果你設定了多個都可能匹配同一 URI 的 location 區塊,那麼請求有可能被錯誤的區塊接管,並被轉發到錯誤的上游伺服器。舉例來說,你可能有一個用於 /api 的 location 區塊,代理到後端 A;還有一個用於 / 的 location 區塊,代理到後端 B。如果 /api 的匹配規則設定不當,那麼存取 /api/login 時,就有可能先命中 /,導致請求被轉給無法處理它的後端 B,最終出現 502。避免這種問題的方法之一,就是檢查 Nginx 設定中 location 區塊的順序。應把更具體的區塊放在兜底區塊之前,必要時使用 = 修飾符進行精確匹配。你還可以用 curl 測試看看到底是哪個 location 區塊在處理請求。理解 location 匹配優先順序,能幫助你更快修復這類路由錯誤。一旦順序確認正確,502 往往也會隨之消失。
修復 PHP-FPM 與 Socket 權限問題
PHP-FPM 是 Nginx 常見的上游之一。若程序池停止執行,或 listen 指令設定錯誤,就會觸發 502 錯誤。你必須驗證程序池狀態以及 socket 權限。這兩項檢查可以解決大多數與 PHP-FPM 有關的 502 問題。
確認 PHP-FPM 程序池狀態
使用 sudo systemctl status php8.1-fpm 檢查 PHP-FPM 程序池狀態。請根據你的實際安裝版本調整版本號。輸出會顯示該程序池是否處於 active 且 running 狀態。如果是 inactive 或 failed,就執行 sudo systemctl start php8.1-fpm 啟動它。很多情況下,這一步就能立刻解決 502。
接下來,驗證 PHP-FPM 程序池設定中的 listen 指令。這個檔案位於 /etc/php-fpm.d/www.conf。listen 指令定義了監聽位址或 socket 路徑。如果它與 Nginx 設定中的 fastcgi_pass 指令不一致,就會導致 502。執行 grep '^listen =' /etc/php-fpm.d/www.conf 查看目前設定,再與 Nginx 設定進行比對。兩者必須完全一致。如果使用的是 Unix socket,那麼路徑必須一字不差;如果使用的是 TCP 位址,那麼連接埠必須相同。
修正 Unix Socket 的擁有權
當 listen 指令使用 Unix socket 時,檔案權限就變得非常關鍵。Nginx 必須對該 socket 檔案擁有讀寫權限。錯誤的擁有權會阻止連線。下表展示了常見的權限設定。
| 設定項 | 預設值 / 範例值 | 用途 |
|---|---|---|
| listen.owner | nobody(預設註解值) | Unix socket 的擁有者 |
| listen.group | nobody(預設註解值) | Unix socket 的所屬群組 |
| listen.mode | 0666(預設註解值) | 權限設定;需要具備讀寫權限 |
| user | apache | PHP-FPM 程序使用者 |
| group | apache | PHP-FPM 程序群組 |
socket 所在目錄同樣需要具備正確的擁有權和權限。下面這條指令展示了一個合適的設定方式。
解決 TLS 握手失敗
如果上游使用 HTTPS,就又多了一個可能出錯的環節。Nginx 連線後端,開始進行 TLS 握手,而協商失敗。代理因此無法收到有效回應,於是回傳 502。憑證問題和協定不匹配都會導致這種結果,而且它們通常不會在存取日誌中留下明顯線索。
驗證上游憑證
憑證過期、自簽憑證,或者憑證所簽發的主機名稱與實際主機名稱不匹配,都會導致握手失敗。Nginx 會拒絕上游身分並關閉連線。在更改任何設定之前,應先從 Nginx 主機直接測試上游。openssl s client 工具會顯示完整的憑證鏈以及驗證結果。
只有當輸出中出現諸如 Verify return code: 0 (ok) 或 Verification: OK 之類的資訊時,憑證檢查才算通過。任何其他回傳碼都可能直接指向根本原因。請將其中的主機名稱和連接埠替換為你自己的上游值。如果你依賴私有 CA,也要確認 CA 檔案與 Nginx 設定中引用的檔案一致。
匹配協定與密碼套件
協定版本或密碼套件不匹配,也會導致握手失敗。上游可能只接受 TLS 1.2,而 Nginx 提供的是其他版本;或者雙方根本沒有共同支援的密碼套件。連線嘗試因此失敗,代理便向用戶端回報 502。
檢查兩端的協定與密碼設定。將 Nginx 設定中的 ssl_protocols 和 ssl_ciphers 指令,與上游伺服器接受的參數進行比對。透過啟用雙方都支援的協定版本或密碼套件,來擴大相容範圍。每次修改後,都應重新載入 Nginx,並再次使用 openssl s client 測試上游。只要握手成功,就表示修復已經生效。
現在,你已經有了一條可重複使用的排查路徑:先看代理錯誤日誌,再檢查上游服務、網路規則、Nginx 設定和安全層。按照這個順序,就能在不靠猜測的前提下,回答「我該如何一步步找到根本原因?」這個問題。
建議你把下面這份清單保存下來,以備下一次事故使用:
- 首先閱讀 Nginx 錯誤日誌。
- 確認上游程序正在執行且正在監聽。
- 使用 curl 或 telnet 測試可達性。
- 驗證 proxy_pass、逾時和緩衝區設定。
- 檢查 SELinux、AppArmor 和 TLS 設定。
同一個 502 Bad Gateway 錯誤,很少會連續兩次由同一個原因引發。持續監控上游健康狀態,經常檢查日誌,並遵循 Nginx 代理最佳實務,能夠預防大多數 502 事件。
常見問題
大多數 502 Bad Gateway 錯誤是由什麼引起的?
最常見的原因是上游伺服器已停止執行或無法存取。後端程序可能已經當機、停止,或者根本沒有啟動。應先檢查代理錯誤日誌,其中的訊息通常會直接指向上游問題。
我要怎麼判斷問題出在 Nginx 還是後端?
Nginx 錯誤日誌會告訴你答案。出現 connection refused 訊息,表示後端已停止;出現 timeout 訊息,表示後端回應過慢。Nginx 只是回報故障,真正的問題仍然在後端。
即使應用執行正常,防火牆也會導致 502 嗎?
會。防火牆規則或雲端安全群組可能會在 Nginx 與上游之間丟棄封包。服務在自己的主機上看起來一切正常,但從 Nginx 主機使用 curl 或 telnet 測試時,就能確認是否存在阻擋。
為什麼 502 只會在高流量時出現?
這通常表示資源耗盡。上游工作執行緒池被占滿,或者資料庫開始變慢。Nginx 持續等待,最終逾時。與其先提高逾時值,不如先查看上游效能指標。
我該如何一步步找到根本原因?
從代理錯誤日誌開始。然後確認上游程序正在執行並處於監聽狀態。接著測試網路可達性。之後再檢查設定、逾時和安全策略。每一層都會進一步縮小範圍,直到你定位真正的故障點。
