
Nginx 與 Apache 的疑難排解
先看日誌,不要猜
多數問題的原因會直接寫在日誌裡。常見位置:
# Nginx /var/log/nginx/error.log /var/log/nginx/access.log # Apache /var/log/apache2/error.log # Debian 系 /var/log/httpd/error_log # RHEL 系 # PHP-FPM /var/log/php8.3-fpm.log
即時觀察:
tail -f /var/log/nginx/error.log
vhost 中若有自訂的日誌路徑,要看那一份,不是預設的。
502 Bad Gateway
代表 Nginx 無法與後端(通常是 PHP-FPM)溝通。
依序檢查
- PHP-FPM 有在跑嗎——
systemctl status php8.3-fpm - socket 路徑對嗎——設定中的
fastcgi_pass與 FPM 的listen是否一致 - 權限對嗎——FPM 的
listen.owner、listen.group需與 Nginx 執行身分相容 - 行程池是否耗盡——FPM 日誌若出現 max_children 相關警告,就是不夠用
- PHP 是否崩潰——查看 FPM 日誌中的異常結束訊息
版本升級後最常見的原因是 socket 路徑改變——例如從 php8.2-fpm.sock 變成 php8.3-fpm.sock,但 Nginx 設定沒有同步更新。
504 Gateway Timeout
後端有回應但太慢,超過等待時間。
fastcgi_read_timeout 120s; proxy_read_timeout 120s;
但拉長逾時只是治標。 應該找出為什麼那麼慢:
- 資料庫查詢沒有索引
- 迴圈中重複查詢
- 呼叫外部 API 而對方無回應
- 批次作業放在網頁請求中執行
批次或匯出類的長時間作業,應該改為背景排程處理,而不是靠拉長逾時。
413 Request Entity Too Large
上傳的檔案超過限制。需要多處一起調整:
# Nginx client_max_body_size 64m; # PHP upload_max_filesize = 64M post_max_size = 72M
post_max_size 要大於 upload_max_filesize,因為除了檔案本身還有其他表單欄位。
Apache 端若有 LimitRequestBody 也需一併調整。
403 Forbidden
常見原因:
- 檔案權限或擁有者不正確
- index 檔案不存在且目錄瀏覽關閉——這其實是正常的
- SELinux 或 AppArmor 的限制——RHEL 系特別常見
- 設定中的 deny 規則誤擋
SELinux 的檢查
getenforce ls -Z /var/www/example
若情境標籤不正確,可用 restorecon -Rv 修正。不建議直接關閉 SELinux。
404 但檔案確實存在
- root 或 alias 路徑設錯——注意 alias 與 root 的行為差異
- location 的比對順序——精確比對與前綴比對的優先順序
- try_files 的順序
- 大小寫——Linux 的檔案系統區分大小寫
用 nginx -T 可以輸出完整的實際設定(含所有 include),確認實際生效的內容。
設定改了沒生效
- 有 reload 嗎
- 改的是實際載入的檔案嗎——用
nginx -T或apachectl -S確認 - sites-enabled 的符號連結建立了嗎
- 有沒有被後面的設定覆蓋——Nginx 的 add_header 繼承規則尤其容易踩到
- 瀏覽器快取——用無痕視窗或 curl 確認
curl -I https://example.com
多個 server 區塊時比對錯誤
Nginx 的 server_name 比對順序:精確名稱 → 星號開頭的萬用 → 星號結尾的萬用 → 正規表示式 → default_server。
若請求落到了非預期的 server 區塊,通常是 server_name 沒有涵蓋該網域,因而落到預設的區塊。
建議明確指定一個 default_server 處理未匹配的請求:
server {
listen 443 ssl default_server;
server_name _;
return 444;
}
日誌的判讀技巧
找出最常見的錯誤
awk '{print $9}' access.log | sort | uniq -c | sort -rn | head
找出 404 最多的路徑
awk '$9==404 {print $7}' access.log | sort | uniq -c | sort -rn | head -20
找出請求量異常的來源
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20
最後一項對判斷異常流量很有用——若單一來源的請求量遠高於其他,可能是掃描或攻擊。
入侵徵兆的判斷見怎麼知道網站被入侵了。
日誌的維護
- 確認 logrotate 有正常運作——日誌長期不輪替會佔滿磁碟
- 靜態檔案的存取可關閉記錄——減少日誌量
- 保留期間要考量個資——存取紀錄含連線位址,屬於個人資料的範疇
磁碟被日誌佔滿是實際會發生的事故,而且症狀是網站突然無法運作。建議把磁碟用量納入監控。
排查的通用順序
- 確認範圍——全站還是特定路徑?所有人還是部分?
- 看錯誤日誌——原因通常直接寫在裡面
- 用 curl 排除瀏覽器因素
- 確認服務狀態——Nginx、PHP-FPM、資料庫
- 確認磁碟與記憶體——
df -h、free -m - 比對最近的變更——設定、部署、系統更新
第六項最有效。 突然出現的問題,幾乎都能對應到某個具體的變更。
本文的設定範例以常見的環境為例,實際的路徑、模組名稱與指令可能因作業系統、版本與安裝方式而異。套用前請先在測試環境驗證,並確實備份原設定檔。