昨天遇到一個(gè) nginx
下非常詭異(其實(shí)也不算難,思路對(duì)了也就1秒鐘的事情)的現(xiàn)象,花了2個(gè)小時(shí)才找到問題并解決,問題的現(xiàn)象還是第一次遇到,記錄下,方便以后的自己和遇到類似問題的同學(xué)。
“PS:下面文章內(nèi)容,是deepseek根據(jù)我們的對(duì)話記錄生成的。本來想自己寫的,但自己寫還是太慢了點(diǎn),為了積極踐行 降本增效 的大方針,還是用更加高效的AI來吧
相關(guān)URL、IP等信息已經(jīng)脫敏處理
一次Nginx臨時(shí)目錄權(quán)限引發(fā)的"詭異"路由問題排查記
“看似相同的請(qǐng)求為何走向不同的終點(diǎn)?一次權(quán)限問題引發(fā)的深度排查
問題現(xiàn)象:兩條相似的請(qǐng)求,不同的目的地
在日常運(yùn)維中,我遇到了一個(gè)奇怪的問題:兩個(gè)具有相同路徑前綴的HTTP請(qǐng)求,竟然被Nginx轉(zhuǎn)發(fā)到了不同的上游服務(wù)器。
查看Nginx訪問日志,發(fā)現(xiàn)了這樣的記錄:
192.168.1.100 - - [02/Sep/2025:17:07:45 +0800] "POST /api/service/v1/file/upload HTTP/1.0" 502 559 "https://example.com/static/webapp/v1/" "Mozilla/5.0 (Linux; Android 15; Build/AQ3A.240912.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.260 Mobile Safari/537.36" upstream_addr=127.0.0.1:9001 upstream_status=502 upstream_response_time=0.001 request_time=0.001
192.168.1.100 - - [02/Sep/2025:17:08:32 +0800] "POST /api/service/v1/user/item/addItem HTTP/1.0" 200 95 "https://example.com/static/webapp/v1/" "Mozilla/5.0 (Linux; Android 15; Build/AQ3A.240912.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.260 Mobile Safari/537.36" upstream_addr=192.168.10.20:8080 upstream_status=200 upstream_response_time=0.124 request_time=0.125
從日志可以看出,兩個(gè)請(qǐng)求都有相同的路徑前綴/api/service/v1/
,但第一個(gè)請(qǐng)求被轉(zhuǎn)發(fā)到了127.0.0.1:9001
并返回502錯(cuò)誤,第二個(gè)請(qǐng)求則被正確轉(zhuǎn)發(fā)到了192.168.10.20:8080
并返回200成功。
排查過程:一步步揭開迷霧
第一階段:增強(qiáng)日志,確認(rèn)問題
首先,我們?cè)贜ginx配置中增加了詳細(xì)的日志格式,希望能夠捕獲更多信息:
log_format detailed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'upstream_addr=$upstream_addr upstream_status=$upstream_status '
'uri=$uri request_uri=$request_uri';
access_log /var/log/nginx/detailed_access.log detailed;
啟用詳細(xì)日志后,我們確認(rèn)了兩個(gè)具有相同前綴的請(qǐng)求確實(shí)被路由到了不同的upstream,這與預(yù)期行為不符。
第二階段:排查location配置
我們檢查了Nginx配置,發(fā)現(xiàn)有兩個(gè)location塊:
location /api/service/v1/ {
proxy_pass http://192.168.10.20:8080/api/;
}
location / {
proxy_pass http://127.0.0.1:9001/;
}
按照Nginx的最長(zhǎng)前綴匹配原則,兩個(gè)請(qǐng)求都應(yīng)該匹配到第一個(gè)location塊。但實(shí)際情況并非如此。
為了排除默認(rèn)location的干擾,我們嘗試注釋掉了第二個(gè)location塊:
# location / {
# proxy_pass http://127.0.0.1:9001/;
# }
重啟Nginx后,驚訝地發(fā)現(xiàn)被錯(cuò)誤轉(zhuǎn)發(fā)請(qǐng)求的upstream_addr變成了空,這表明請(qǐng)求根本沒有被正確代理到任何上游服務(wù)器。
第三階段:發(fā)現(xiàn)關(guān)鍵錯(cuò)誤日志
在前兩個(gè)階段都沒有找到根本原因后,我們幾乎是無意中查看了Nginx的錯(cuò)誤日志( error.log ) ,這才發(fā)現(xiàn)了關(guān)鍵線索:
2025/09/03 07:58:41 [crit] 1340742#0: *277929 open() "/usr/local/nginx/client_body_temp/0000000054" failed (13: Permission denied), client: 192.168.1.100, server: example.com, request: "POST /api/service/v1/file/upload HTTP/1.0", host: "api.example.com", referrer: "https://example.com/static/webapp/v1/"
這個(gè)錯(cuò)誤信息很關(guān)鍵——Nginx進(jìn)程沒有權(quán)限在臨時(shí)目錄中創(chuàng)建文件。
根源分析:臨時(shí)目錄與Nginx的fallback機(jī)制
1. Nginx如何處理大請(qǐng)求體
當(dāng)Nginx處理客戶端請(qǐng)求時(shí),如果請(qǐng)求體較小,會(huì)使用內(nèi)存緩沖區(qū)直接處理。但當(dāng)請(qǐng)求體較大(超過client_body_buffer_size
設(shè)置)時(shí),Nginx會(huì)將請(qǐng)求體寫入臨時(shí)文件中,以避免占用過多內(nèi)存。
2. 權(quán)限失敗引發(fā)的連鎖反應(yīng)
當(dāng)?shù)谝粋€(gè)請(qǐng)求(文件上傳)到達(dá)時(shí):
- 由于請(qǐng)求體較大,Nginx嘗試將其寫入臨時(shí)文件
- 但Nginx worker進(jìn)程沒有臨時(shí)目錄的寫權(quán)限
- 觸發(fā)了Nginx的錯(cuò)誤處理機(jī)制,將請(qǐng)求fallback到默認(rèn)location
而第二個(gè)請(qǐng)求(普通API調(diào)用):
- 請(qǐng)求體較小,不需要寫入臨時(shí)文件
- 因此沒有觸發(fā)權(quán)限錯(cuò)誤
解決方案:創(chuàng)建有權(quán)限的臨時(shí)目錄
通過以下步驟解決了這個(gè)問題:
1. 創(chuàng)建有權(quán)限的臨時(shí)目錄
mkdir -p /tmp/nginx_temp/client_body_temp
2. 在nginx.conf中配置臨時(shí)目錄路徑
在http塊中添加配置:
http {
# 其他配置...
# 指定臨時(shí)目錄到有權(quán)限的位置
client_body_temp_path /tmp/nginx_temp/client_body_temp;
# 其他配置...
}
3. 確保Nginx進(jìn)程有讀寫權(quán)限
chown -R nginx:nginx /tmp/nginx_temp/client_body_temp
chmod -R 755 /tmp/nginx_temp/client_body_temp
4. 重新加載Nginx配置
nginx -s reload
經(jīng)驗(yàn)總結(jié)與反思
這次排查經(jīng)歷給了我們幾個(gè)重要啟示:
- 日志是關(guān)鍵:沒有詳細(xì)的訪問日志和錯(cuò)誤日志,很難快速定位問題
- 排查要有系統(tǒng)性:從表象到本質(zhì),從access.log到error.log,需要有條不紊地進(jìn)行
- 權(quán)限問題很隱蔽:Nginx的權(quán)限問題往往表現(xiàn)為其他癥狀,需要深入挖掘
- 默認(rèn)配置可能不適用:生產(chǎn)環(huán)境中需要明確指定各種路徑和權(quán)限,不能依賴默認(rèn)值
排查過程中的關(guān)鍵步驟:
- 增加詳細(xì)日志記錄,確認(rèn)問題現(xiàn)象
- 通過修改配置(注釋默認(rèn)location)縮小問題范圍
- 檢查錯(cuò)誤日志,發(fā)現(xiàn)根本原因
預(yù)防措施與最佳實(shí)踐
為了避免類似問題,建議采取以下措施:
# 示例:完整的客戶端請(qǐng)求體配置
http {
client_max_body_size 100M;
client_body_buffer_size 16k;
client_body_temp_path /var/tmp/nginx_client_temp;
client_body_timeout 60s;
# 確保目錄存在且有權(quán)限
# mkdir -p /var/tmp/nginx_client_temp
# chown -R nginx:nginx /var/tmp/nginx_client_temp
# chmod -R 755 /var/tmp/nginx_client_temp
}
親愛的讀者朋友們,歡迎在評(píng)論區(qū)分享你的經(jīng)驗(yàn)和見解!
?? 討論話題:
- 你在使用Nginx過程中遇到過哪些"詭異"的問題?最后是如何解決的?
- 關(guān)于Nginx的權(quán)限管理,你有哪些最佳實(shí)踐想要分享?
- 本文的排查思路對(duì)你是否有啟發(fā)?你會(huì)如何避免類似的坑?
?? 如果你覺得這篇文章對(duì)你有幫助:
- 點(diǎn)贊支持一下,讓更多小伙伴看到這篇干貨
- 關(guān)注我們,獲取更多運(yùn)維實(shí)戰(zhàn)經(jīng)驗(yàn)和技巧分享
- 收藏文章,遇到類似問題時(shí)隨時(shí)回來查閱
?? 延伸思考:
- 除了臨時(shí)目錄權(quán)限,還有哪些看似小卻可能引發(fā)大問題的Nginx配置細(xì)節(jié)?
- 在你的生產(chǎn)環(huán)境中,是如何監(jiān)控和預(yù)防這類權(quán)限問題的?
閱讀原文:原文鏈接
該文章在 2025/9/8 9:33:29 編輯過