Nginx靜態服務配置---詳解root和alias指令
原文:https://www.jianshu.com/p/4be0d5882ec5
靜態文件
Nginx以其高性能著稱,常用與做前端反向代理服務器。同時nginx也是一個高性能的靜態文件服務器。通常都會把應用的靜態文件使用nginx處理。
配置nginx的靜態文件有兩個指令,一個 root 和一個 alias。對於這兩個指令,是否需要在路徑的后面加上斜杠,經常容易讓人犯暈,本文通過嘗試不同的匹配規則,歸納了一個比較通用的配置方式。
基本配置
與簡明 Nginx Location Url 配置筆記一文關於location url配置的實驗一樣,本文也使用vagrant虛擬機里的nginx。其基本配置如下:
/etc/nginx/sites-enabled/pro.conf
server {
listen 80 default_server; server_name localhost; access_log /var/log/nginx/pro/access.log; error_log /var/log/nginx/pro/error.log; error_page 404 /404.html; root /vagrant/pro; index index.html index.htm; }
項目的目錄如下:
☁ pro tree . ├── 403.html ├── 404.html ├── index.html ├── static │ ├── flask │ │ └── m.png │ └── stc.jpg └── upload └── up.png 3 directories, 6 files
分別有兩個靜態文件夾,一個是static,另外一個是upload。
初識root
root 是指定項目的根目錄,適用與server和location。可以指定多個,如果locaiton沒有指定,會往其外層的server或http中尋找繼承。
訪問http://192.168.33.10/static/stc.jpg
會發現圖片已經返回。我們還尚未配置 location,為啥會正確的找到文件?學習root
或者alias
指令的時候,最好的辦法是給文件拓展名加上一個字符,使得該文件在硬盤中不存在,那么就能從nginx
的error.log
中看到nginx尋找文件的方式。
訪問 http://192.168.33.10/static/stc.jpgx
,然后查看 /var/log/nginx/pro/error.log
文件,可以看到如下的錯誤信息:
2016/09/28 07:41:48 [error] 4416#0: *70 open() "/vagrant/pro/static/stc.jpgx" failed (2: No such file or directory), client: 192.168.33.1, server: localhost, request: "GET /static/stc.jpgx HTTP/1.1", host: "192.168.33.10"
即/vagrant/pro/static/stc.jpgx
文件不存在。的確我們沒有這個文件。如果文件名正確,就能訪問,原因是由於在server中指定了root /vagrant/pro
,此時的nginx就在該目錄下尋找文件,而url上的地址,正好和文件的路徑一致
http://192.168.33.10 /static/stc.jpg /vagrant/pro /static/stc.jpg
由此可以猜想,nginx中root指令的地址,其實是替換了匹配后的url中的host。
root指令
為了驗證上面的猜想,需要多寫幾個location做實驗。添加一個location配置如下:
location ^~ /static { root /vagrant/pro/static; }
再次訪問http://192.168.33.10/static/stc.jpg
,發現並不能顯示圖片了,查看error.log 返回如下:
2016/09/28 07:48:57 [error] 5978#0: *71 open() "/vagrant/pro/static/static/stc.jpg" failed (2: No such file or directory), client: 192.168.33.1, server: localhost, request: "GET /static/stc.jpg HTTP/1.1", host: "192.168.33.10"
nginx把地址識別成/vargrant/pro/static/static/stc.jpg
多了一個static,套用上面的規則,其組合為192.168.33.10
== /vagrant/pro/static
,url是/static/stc.jpg
。置換可以得到/vagrant/pro/static
+ /static/stc.jpg
。與錯誤的error一致。解決方案就是把root中的static去掉,馬上就能訪問圖片了。
既然是那么把文件夾static
命名為stc
,其結果又會怎樣?
location ^~ /static { root /vagrant/pro; }
訪問 http://192.168.33.10/static/stc.jpg
得到錯誤:
2016/09/28 07:54:46 [error] 5992#0: *73 open() "/vagrant/pro/static/stc.jpg" failed (2: No such file or directory), client: 192.168.33.1, server: localhost, request: "GET /static/stc.jpg HTTP/1.1", host: "192.168.33.10"
計算路徑/vagrant/pro
+ /static/stc.jpg
, 找不到/vagrant/pro/static/stc.jpg
文件,符合之前所說的規則,嘗試修改location:
location ^~ /stc {
root /vagrant/pro;
}
因為url變了,訪問http://192.168.33.10/stc/stc.jpg
,才能夠找到圖片。現在把stc文件夾變回static。
root 與 斜杠
很多人會疑惑,路徑最后的斜杠/
是否要加呢?location中的static后面的斜杠,和匹配后的url有關,不再贅述。root中的路徑的斜杠/
可以再通過實驗確定。把location配置如下:
location ^~ /static/ { root /vagrant/pro/; }
訪問http://192.168.33.10/static/stc.jpg
一切正常,訪問http://192.168.33.10/static/stc.jpg
,error為找不到"/vagrant/pro/static/stc.jpgs"文件。
如果按照root替換host的規則,那么替換過程為
/vagrant/pro/
+ /static/stc.jpg
== /vagrant/pro//static/stc.jpg
。在*nix系統中, 多個斜杠和一個斜杠是等價的,也就是 /vagrant/pro//static/stc.jpg
與/vagrant/pro/static/stc.jpg
一樣。
這樣一來,root路徑后面的斜杠,加與不加效果都一樣。既然如此,肯定有人會想到這么配置:
location ^~ static/ { root /vagrant/pro; }
如果安裝之前上面的即算法,那么應該是 /vagrant/pro
+ static/stc.jpg
,相加的應該是/vagrant/prostatic/stc.jpg
,按理說應該是錯誤,可是實際上卻能訪問圖片。咄咄怪事?
如果對前文nginx location的url匹配規則了解的話,應該看出來了其實 ^~ static/
並不能匹配。修改 location
location ^~ static/ { rewrite ^ http://google.com; # root /vagrant/pro; }
訪問http://192.168.33.10/static/stc.jpg
依然可以得到圖片,沒有跳轉google,說明並沒有匹配^~ static/
。
其實原理也很簡單,還記得我們第一次實驗,當時尚未配置location,也同樣可以返回圖片。沒錯,盡管^~ static/
沒有匹配,而外層的server定義了root為/vagrant/pro
,因此搜索圖片正常返回,再注釋外層的root,再一次訪問。此時會得到一個404,查看error如下:
2016/09/28 08:18:15 [error] 6227#0: *82 open() "/usr/share/nginx/html/static/stc.jpg" failed (2: No such file or directory), client: 192.168.33.1, server: localhost, request: "GET /static/stc.jpg HTTP/1.1", host: "192.168.33.10"
/usr/share/nginx/html/static/stc.jpg
,說明即使沒有指定root,nginx默認也有一個root,/usr/share/nginx/html
。當然,這個配置和 ^~ static/
沒有關系。
如果~ static/stc.jpgs?
那么就能命中,此時訪問圖片,依然能夠正確的解析,因此,並不存在 /vagrant/pro
+ static/stc.jpg
這種情況。理解這里的關鍵是 root替換host,並加上匹配后的url,匹配后的url當然包括前面的斜杠,匹配部分的url則不會。
對於 ~ static/stc.jpgs?
模式,訪問urlhttp://192.168.33.10/static/stc.jpg
- 匹配后的url為 /static/stc.jpg
- 匹配部分的url為 static/stc.jpg
掌握這個很重要,直接關系到后面alias
指令與斜杠的關系。
對於root指令,我們可以歸納。
- 對於匹配后的url地址,將匹配的location中的root路徑替換訪問url的host即得到文件的真實地址。(多個斜杠其實等價於一個斜杠)
- 如果不匹配location,則尋找更外層的root做替換。
- root指令最后的斜杠可加可不加。
alias指令
對於root,操作上很簡單,只要把root地址替換host后就是文件在硬盤路徑(真實地址)。對於alise,它並不是替換匹配后的url地址,而是替換匹配部分的url。alias指令也可以有多個。
添加一個location,和root的方式幾乎一樣:
location ^~ /upload {
alias /vagrant/pro; }
訪問http://192.168.33.10/upload/up.png
並沒有圖片,查看error得到:
2016/09/28 08:36:18 [error] 6312#0: *90 open() "/vagrant/pro/up.png" failed (2: No such file or directory), client: 192.168.33.1, server: localhost, request: "GET /upload/up.png HTTP/1.1", host: "192.168.33.10"
可見 alias的模式並不是/vagrant/pro
+ /upload/up.png
,而是 /vagrant/pro
+ /up.png
。
alias這個詞在計算機里很常用,字面意思是“別名”,顧名思議就是換一個名字啦。實際替換規則就是把匹配的url地址,換成alias中的路徑即可。例如上述的例子替換過程可以模擬如下:
過程 | 模式或url |
---|---|
url模式 | ^~ /upload |
alias路徑 | /vagrant/pro |
訪問地址 | http://192.168.33.10/upload/up.png |
匹配部分的地址 | /upload + /up.png |
替換 | /upload == /vagrant/pro |
結果 | /vagrant/pro + /up.png |
為了修改圖片的訪問,修改locaton如下:
location ^~ /upload {
alias /vagrant/pro/upload; }
此時訪問http://192.168.33.10/upload/up.png
就能得到正確的圖片啦,仿造上面的計算過程為:
過程 | 模式或url |
---|---|
url模式 | ^~ /upload |
alias路徑 | /vagrant/pro/upload |
訪問地址 | http://192.168.33.10/upload/up.png |
匹配部分的地址 | /upload + /up.png |
替換 | /upload == /vagrant/pro/upload |
結果 | /vagrant/pro/upload + /up.png |
從結果可以看出,正確的找到了文件路徑,如果alias指令路徑加上斜杠,那么計算處理的文件路徑為:
/upload == /vagrant/pro/upload
/vagrant/pro/upload/ + /up.png
多個斜杠是合法的。等價於一個斜杠的情況。
下面修改locaiton如下:
location ^~ /upload/ { alias /vagrant/pro/upload; }
此時匹配時的url則變成 /upload/ + up.jpg
, 那么置換的結果為 /vagrant/pro/upload
+ up.png
,而/vagrant/pro/uploadup.png
的路徑是非法的,從error中也能看到置換的錯誤:
2016/09/28 08:52:44 [error] 6452#0: *92 open() "/vagrant/pro/uploadup.png" failed (2: No such file or directory), client: 192.168.33.1, server: localhost, request: "GET /upload/up.png HTTP/1.1", host: "192.168.33.10"
解決辦法也很簡單,把/vagrant/pro/upload
改成 /vagrant/pro/upload/
即可。由此可見,alias最后的斜杠並不像root指令那樣可有可無,是否需要,取決於配合loacation的url匹配模式。
前文root模式中,考慮了沒有根的斜杠(~ static/stc.jpgs?
)這種情況,alias情況下會很難捕捉錯誤。如果locaion配置如下:
location ^~ upload/ {
alias /vagrant/pro/upload/; }
替換置換的文件路徑應該為 /vagrant/pro/upload/up.png
,可是實際測試中,這樣配置alias,會一直導致一個301的重定向,如果alias目錄沒有打開autoindex,則會拋出一個403錯誤。具體情況尚未知曉,不知道是不是nginx的bug。為了避免這種情況,使用alias的時候,盡量不要配置location為 ^~ upload/
的模式,並且不從根指定url,還是顯得不倫不類。
alise作為別名,比起root的一大好處就是不一定要url上的路徑和文件路徑一樣,因為alise並不是替換host,而是替換匹配部分的host。修改配置如下:
location ^~ /upload/ { alias /vagrant/pro/static/; }
訪問 http://192.168.33.10/upload/stc.jpg
或者 http://192.168.33.10/upload/flask/m.png
都能正確的訪問到static目錄下的文件,盡管url上是upload。
替換規則也很簡單,/upload/
== /vagrant/pro/static/
得到 /vagrant/pro/static/
+ stc.jpg
或 /vagrant/pro/static/
+ flask/m.png
。
總結
nginx的靜態文件配置中,root和alias指令都能實現。為了避免混淆,盡量不要寫沒有根路徑的url模式,即避免 static/
這樣的開頭,根路徑的斜杠需要保留,沒有根路徑其實也很奇怪。
root和alias的區別主要在於替換的部分,root模式中,會把root配置的路徑替換匹配后的url中的host。alias則把他指定的路徑,替換url中匹配的部分。指令中的斜杠對於root指令沒有影響,對於alise則按照替換規則匹配即可。
root 指令
location /dir/
root root_path -> http://host/dir/file.txt -> root_path/dir/file.txt
alias 指令
location /dir
alias alias_path -> http://host /dir /file.txt -> alias_path/file.txt location /dir/ alias alias_path/ -> http://host /dir/ file.txt -> alias_path/file.txt
了解了root和alise之后,通常最佳實際是配置一個項目的根root,其他的文件夾則使用alias,畢竟alias更加靈活。
作者:人世間
鏈接:https://www.jianshu.com/p/4be0d5882ec5
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。