執(zhí)行Nginx -t會導(dǎo)致文件所有者權(quán)限變?yōu)镹obody,你知道嗎?
故障現(xiàn)象
最近生產(chǎn)環(huán)境出現(xiàn)了1次app應(yīng)用登錄異常的故障,最后定位分析發(fā)現(xiàn)是因為在root用戶下執(zhí)行過nginx -t命令導(dǎo)致部分文件目錄(1、fastcgi、proxy、scgi、uwsgi)所有者權(quán)限變?yōu)閚obody導(dǎo)致。其實在nginx應(yīng)用的error日志中也發(fā)現(xiàn)有大量權(quán)限問題的相關(guān)報錯:[crit] 123744#0: *172221779 open() "/app/nginx20/1/21/0118488121" failed (13: Permission denied),只不過一開始沒引起重視,因為查看有權(quán)限報錯的這些目錄下并沒有任何文件,加上也咨詢過研發(fā)認為沒有影響,所以導(dǎo)致一開始的排查方向出現(xiàn)了偏差,最終導(dǎo)致此次故障還是經(jīng)歷了好幾個小時。
原因分析
那么為什么執(zhí)行nginx -t命令會導(dǎo)致臨時文件所有者權(quán)限變?yōu)閚obody,這才是寫這篇文章的目的,下面進行測試。Nginx -t命令官方解釋如下:
按照官網(wǎng)對nginx -t命令的解釋,該命令只是去檢查配置文件語法,并打開配置文件中預(yù)定義文件,按照這個字面意思理論上該命令不會對文件目錄權(quán)限進行修改,但是在實際測試過程中發(fā)現(xiàn)使用普通用戶如app運行nginx服務(wù),并且nginx配置文件nginx.conf中沒有配置user xxx參數(shù)內(nèi)容時,如果使用root用戶執(zhí)行nginx -t命令,則會導(dǎo)致臨時文件(fastcgi、scgi、uwsgi、client_body、proxy)目錄權(quán)限所有者被更改為nobody,這使得啟動 nginx 服務(wù)的用戶失去了對這些目錄的訪問權(quán)限,從而引發(fā)應(yīng)用程序的部分頁面無法訪問的問題。觸發(fā)此問題的具體條件如下::
1)nginx服務(wù)進程使用非root和nobody用戶啟動;
2)nginx配置文件nginx.conf中缺少啟動用戶的定義:即配置文件中沒有包含user app;這樣的行來指定nginx服務(wù)啟動時所使用的用戶
3)使用root用戶執(zhí)行了nginx -t命令:這可能會在上述兩個條件下更改臨時目錄的所有者為 nobody
測試驗證
為了驗證上述結(jié)論是否成立,我們進行以下測試驗證。在/opt目錄下安裝了一個nginx應(yīng)用,授權(quán)所有文件歸屬user及group為app用戶。
[root@localhost opt]# chown -R app.app /opt/nginx20/
[root@localhost opt]# ll /opt/nginx20/
total 36K
drwx------ 2 app app 4.0K Aug 27 20:50 client_body_temp
drwxr-xr-x 2 app app 4.0K Aug 27 22:29 conf
drwx------ 2 app app 4.0K Aug 27 20:50 fastcgi_temp
drwxr-xr-x 2 app app 4.0K Aug 27 20:49 html
drwxr-xr-x 2 app app 4.0K Aug 27 22:34 logs
drwx------ 2 app app 4.0K Aug 27 20:50 proxy_temp
drwxr-xr-x 2 app app 4.0K Aug 27 20:49 sbin
drwx------ 2 app app 4.0K Aug 27 20:50 scgi_temp
drwx------ 2 app app 4.0K Aug 27 20:50 uwsgi_temp
然后我們切換到app用戶來啟動nginx(此時nginx.conf配置文件中是未配置 user app;內(nèi)容的)
[root@localhost nginx20]# su - app
[app@localhost ~]$ /opt/nginx20/sbin/nginx -c /opt/nginx20/conf/nginx.conf
[app@localhost ~]$ ps -ef | grep nginx
app 1712 1 0 21:46 ? 00:00:00 nginx: master process /opt/nginx20/sbin/nginx -c /opt/nginx20/conf/nginx.conf
app 1713 1712 0 21:46 ? 00:00:00 nginx: worker process
app 1715 1660 0 21:47 pts/0 00:00:00 grep --color=auto nginx
接下來再次切換到root用戶執(zhí)行nginx -t命令
[root@localhost nginx20]# ll
total 36K
drwx------ 2 app app 4.0K Aug 27 20:50 client_body_temp
drwxr-xr-x 2 app app 4.0K Sep 29 21:46 conf
drwx------ 2 app app 4.0K Aug 27 20:50 fastcgi_temp
drwxr-xr-x 2 app app 4.0K Aug 27 20:49 html
drwxr-xr-x 2 app app 4.0K Sep 29 21:46 logs
drwx------ 2 app app 4.0K Aug 27 20:50 proxy_temp
drwxr-xr-x 2 app app 4.0K Aug 27 20:49 sbin
drwx------ 2 app app 4.0K Aug 27 20:50 scgi_temp
drwx------ 2 app app 4.0K Aug 27 20:50 uwsgi_temp
#上面是執(zhí)行nginx -t命令之前的文件權(quán)限
[root@localhost nginx20]# /opt/nginx20/sbin/nginx -t
nginx: the configuration file /opt/nginx20/conf/nginx.conf syntax is ok
nginx: configuration file /opt/nginx20/conf/nginx.conf test is successful
# 下面是執(zhí)行nginx -t命令之后的文件權(quán)限
[root@localhost nginx20]# ll
total 36K
drwx------ 2 nobody app 4.0K Aug 27 20:50 client_body_temp
drwxr-xr-x 2 app app 4.0K Sep 29 21:46 conf
drwx------ 2 nobody app 4.0K Aug 27 20:50 fastcgi_temp
drwxr-xr-x 2 app app 4.0K Aug 27 20:49 html
drwxr-xr-x 2 app app 4.0K Sep 29 21:46 logs
drwx------ 2 nobody app 4.0K Aug 27 20:50 proxy_temp
drwxr-xr-x 2 app app 4.0K Aug 27 20:49 sbin
drwx------ 2 nobody app 4.0K Aug 27 20:50 scgi_temp
drwx------ 2 nobody app 4.0K Aug 27 20:50 uwsgi_temp
通過上述測試證實了前面說的3點:
1)nginx服務(wù)進程使用非root和nobody用戶啟動;
2)nginx配置文件nginx.conf中缺少啟動用戶的定義:即配置文件中沒有包含user app;
3)使用root用戶執(zhí)行了nginx -t命令:
這種情況下會更改某些目錄的所有者權(quán)限為nobody,上面的client_body_temp、fastcgi_temp、proxy_temp、scgi_temp、uwsgi_temp目錄文件所有者權(quán)限均變?yōu)榱薾obody。
接下來再來驗證下在配置文件中配置啟動用戶的情況,在nginx配置文件中配置user app;內(nèi)容(指定nginx啟動用戶為app)
[root@localhost nginx20]# vim /opt/nginx20/conf/nginx.conf
[root@localhost nginx20]# head -5 /opt/nginx20/conf/nginx.conf
user app;
worker_processes 1;
......
然后直接通過root用戶啟動nginx服務(wù),可以發(fā)現(xiàn)nginx的worker進程運行用戶為app,此時nginx安裝路徑下的文件權(quán)限也為app,前面*temp的幾個文件開始所有者權(quán)限為nobody,在配置文件配置user app內(nèi)容后重新啟動權(quán)限也隨之改變了過來,說明 user app配置內(nèi)容是生效的。
[root@localhost nginx20]# ps -ef | grep nginx
root 1760 1 0 22:04 ? 00:00:00 nginx: master process /opt/nginx20/sbin/nginx -c /opt/nginx20/conf/nginx.conf
app 1761 1760 0 22:04 ? 00:00:00 nginx: worker process
root 1763 1326 0 22:04 pts/0 00:00:00 grep --color=auto nginx
[root@localhost nginx20]# ll
total 36K
drwx------ 2 app app 4.0K Aug 27 20:50 client_body_temp
drwxr-xr-x 2 app app 4.0K Sep 29 22:02 conf
drwx------ 2 app app 4.0K Aug 27 20:50 fastcgi_temp
drwxr-xr-x 2 app app 4.0K Aug 27 20:49 html
drwxr-xr-x 2 app app 4.0K Sep 29 22:04 logs
drwx------ 2 app app 4.0K Aug 27 20:50 proxy_temp
drwxr-xr-x 2 app app 4.0K Aug 27 20:49 sbin
drwx------ 2 app app 4.0K Aug 27 20:50 scgi_temp
drwx------ 2 app app 4.0K Aug 27 20:50 uwsgi_temp
接下來我們在不停nginx服務(wù)的情況下通過chown命令直接改變文件的歸屬權(quán)限,然后再次執(zhí)行nginx -t命令看看
[root@localhost nginx20]# useradd -s /sbin/nologin weihu
[root@localhost nginx20]# chown -R weihu.weihu /opt/nginx20/
[root@localhost nginx20]# ll
total 36K
drwx------ 2 weihu weihu 4.0K Aug 27 20:50 client_body_temp
drwxr-xr-x 2 weihu weihu 4.0K Sep 29 22:02 conf
drwx------ 2 weihu weihu 4.0K Aug 27 20:50 fastcgi_temp
drwxr-xr-x 2 weihu weihu 4.0K Aug 27 20:49 html
drwxr-xr-x 2 weihu weihu 4.0K Sep 29 22:04 logs
drwx------ 2 weihu weihu 4.0K Aug 27 20:50 proxy_temp
drwxr-xr-x 2 weihu weihu 4.0K Aug 27 20:49 sbin
drwx------ 2 weihu weihu 4.0K Aug 27 20:50 scgi_temp
drwx------ 2 weihu weihu 4.0K Aug 27 20:50 uwsgi_temp
#上面直接新建了一個weihu用戶然后授權(quán)/opt/nginx20/及其下的所有文件歸屬為weihu用戶
#下面直接在root用戶下執(zhí)行nginx -t命令
[root@localhost nginx20]# /opt/nginx20/sbin/nginx -t
nginx: the configuration file /opt/nginx20/conf/nginx.conf syntax is ok
nginx: configuration file /opt/nginx20/conf/nginx.conf test is successful
[root@localhost nginx20]# ll
total 36K
drwx------ 2 app weihu 4.0K Aug 27 20:50 client_body_temp
drwxr-xr-x 2 weihu weihu 4.0K Sep 29 22:02 conf
drwx------ 2 app weihu 4.0K Aug 27 20:50 fastcgi_temp
drwxr-xr-x 2 weihu weihu 4.0K Aug 27 20:49 html
drwxr-xr-x 2 weihu weihu 4.0K Sep 29 22:04 logs
drwx------ 2 app weihu 4.0K Aug 27 20:50 proxy_temp
drwxr-xr-x 2 weihu weihu 4.0K Aug 27 20:49 sbin
drwx------ 2 app weihu 4.0K Aug 27 20:50 scgi_temp
drwx------ 2 app weihu 4.0K Aug 27 20:50 uwsgi_temp
通過上述測試可以發(fā)現(xiàn)即使nginx的相關(guān)文件所有者權(quán)限為其他用戶,如果在配置文件中配置了user app;內(nèi)容,那么在執(zhí)行nginx -t 命令后,部分文件的所有者權(quán)限仍舊會改變?yōu)閍pp用戶。
注意:這里的部分文件是指nginx運行時產(chǎn)生的臨時文件,如上面提到的client_body_temp、fastcgi_temp、proxy_temp、scgi_temp、uwsgi_temp等目錄文件,有關(guān)這類臨時文件用途說明如下:
- client_body_temp:這個目錄用于存儲客戶端請求中的大請求體(如 POST 請求)。當(dāng)客戶端發(fā)送的數(shù)據(jù)量超過一定閾值時,Nginx 會將這部分數(shù)據(jù)寫入磁盤上的臨時文件中,以防止占用過多內(nèi)存。
- fastcgi_temp:這個目錄用于存儲通過 FastCGI 協(xié)議傳遞的數(shù)據(jù)。當(dāng) Nginx 作為 FastCGI 網(wǎng)關(guān)時,它可能會將從后端應(yīng)用程序接收到的響應(yīng)數(shù)據(jù)暫時保存在這個目錄中。
- proxy_temp:這個目錄用于存儲通過代理(Proxy)傳遞的數(shù)據(jù)。當(dāng) Nginx 作為反向代理服務(wù)器時,它可能會將從后端服務(wù)器接收到的響應(yīng)數(shù)據(jù)暫時保存在這個目錄中。
- scgi_temp:這個目錄用于存儲通過 SCGI 協(xié)議傳遞的數(shù)據(jù)。SCGI(Simple Common Gateway Interface)是一種類似于 FastCGI 的協(xié)議,用于 Web 服務(wù)器和應(yīng)用程序之間的通信。Nginx 可能會將通過 SCGI 接收到的數(shù)據(jù)暫時保存在這里。
- uwsgi_temp:這個目錄用于存儲通過 uWSGI 協(xié)議傳遞的數(shù)據(jù)。uWSGI 是一個通用的應(yīng)用程序服務(wù)器,支持多種協(xié)議,包括 uWSGI 協(xié)議、FastCGI 協(xié)議等。Nginx 可能會將通過 uWSGI 接收到的數(shù)據(jù)暫時保存在這個目錄中。
這些臨時目錄的主要目的是為了提高性能并避免內(nèi)存溢出。通過將部分數(shù)據(jù)存儲在磁盤上,Nginx 可以有效地處理大請求和響應(yīng)數(shù)據(jù),而不會消耗過多的內(nèi)存資源。
配置建議
為了防止這種情況發(fā)生,生產(chǎn)環(huán)境還是建議在nginx配置文件中明確指定nginx應(yīng)用啟動用戶(如user app;),這將即可避免因錯誤的執(zhí)行了nginx -t命令而導(dǎo)致臨時文件權(quán)限異常進而觸發(fā)業(yè)務(wù)異常的情況出現(xiàn)。