1、nginx配置概覽
概覽
一個(gè)典型的nginx配置文件是由一系列的server塊組成。而每個(gè)server塊是有一系列的location塊組成。server塊是nginx從邏輯上劃分出來的一個(gè)個(gè)的虛擬服務(wù)器,可以從邏輯上認(rèn)為你的服務(wù)器變成多個(gè)了。block塊定義了一個(gè)url路徑該如何定位到正式的文件??傮w來說,nginx處理一個(gè)請(qǐng)求的時(shí)候,先根據(jù)(ip地址,port端口,domain域名)來確定下由哪一個(gè)server塊來進(jìn)行處理,然后server塊再根據(jù)請(qǐng)求的地址來進(jìn)行l(wèi)ocation塊的挑選,location塊內(nèi)部的規(guī)則最終確定下這個(gè)請(qǐng)求怎么返回(直接返回文件內(nèi)容,還是映射成其他請(qǐng)求,還是傳給其他服務(wù)執(zhí)行)。
例子
server {
listen 123.123.123.123:80;
server_name lab.example.com;
root /var/www/html;
index index.html;
location /eg {
try_files $uri $uri/ =404;
}
location /cs {
try_files $uri $uri/ =404;
}
}
server {
listen 123.123.123.123:80;
server_name visit.example.com;
root /var/www/visit;
index index.html;
location = /test {
try_files $uri $uri/ =404;
}
location ^~ /lalal {
try_files $uri $uri/ =404;
}
}
如果我們?cè)L問鏈接http://lab.example.com:80/cs/image.jpg那么就會(huì)由第一個(gè)server的第二個(gè)location來處理。流程是什么樣的呢:
- step 1 挑選server
- 檢查ip和port
nginx發(fā)現(xiàn)請(qǐng)求的ip:port為123.123.123.123:80,對(duì)了一下自己的server列表,發(fā)現(xiàn)兩個(gè)server都滿足。于是要進(jìn)行下一步的檢查 - 檢查domain域名
nginx發(fā)現(xiàn)請(qǐng)求的域名為lab.example.com,這下只有第一個(gè)server滿足了,就指派了第一個(gè)server進(jìn)行處理。 - step 2 挑選location
請(qǐng)求的location為/cs/image.jpg,第一個(gè)location是匹配以/eg開頭的地址不滿足匹配,第二個(gè)location是匹配以/cs開頭的地址,成功匹配。所以就選了第二個(gè)block進(jìn)行處理。 - step3 具體處理
具體處理中是try_files $uri $uri/=404,這里$uri=cs/image.jpg,也就是查看cs/image.jpg這個(gè)文件在/var/www/html目錄下是否存在(全路徑為/var/www/html/cs/image.jpg),如果存在就當(dāng)做文件返回內(nèi)容,如果不存在那么就返回404.
這樣就完成了一個(gè)完整的鏈接請(qǐng)求。
2、server塊詳解
server塊最重要的兩個(gè)屬性是listen和server_name。當(dāng)請(qǐng)求來臨時(shí),listen屬性先用來匹配,如果匹配到唯一server塊那么就是這個(gè)server塊進(jìn)行服務(wù)(就不用考慮server_name是否匹配上了);如果匹配不是唯一的,那么就繼續(xù)使用server_name進(jìn)行匹配。
| 屬性 | 含義 |
|---|---|
| listen | 定義了該虛擬服務(wù)器監(jiān)聽的ip和port對(duì),只有當(dāng)ip和port同時(shí)匹配的時(shí)候才進(jìn)行下一步匹配 |
| server_name | 定義了該虛擬服務(wù)器監(jiān)聽的主機(jī)名,用于當(dāng)ip和port無法確定唯一server塊時(shí)啟用,進(jìn)行進(jìn)一步區(qū)分 |
listen屬性詳解
- 屬性格式
| 形式 | 描述 | 例子 | 默認(rèn)補(bǔ)全 |
|---|---|---|---|
| ip地址+port端口 | 完整形式 | listen 123.123.123.123:23 | listen 123.123.123.123:23 |
| 只有ip | 會(huì)自動(dòng)加上80的web監(jiān)聽端口 | listen 2.2.2.2 | listen 2.2.2.2:80 |
| 只有ip | 會(huì)自動(dòng)加上0.0.0.0的全監(jiān)聽地址 | listen 45 | listen 0.0.0.0:45 |
- 匹配規(guī)則
第一步 當(dāng)nginx匹配的時(shí)候,會(huì)將縮寫的格式補(bǔ)全
第二步 匹配描述的最精確的(縮寫的沒有完整的格式準(zhǔn)確)
第三步 如果第二步的情況下還有多個(gè),那么listen就判斷不出來了,交給server_name判斷
server_name屬性詳解
- 屬性格式
| 形式 | 例子 |
|---|---|
| 不帶有通配符* | www.example.com |
| 帶有前綴通配符* | *.example.com |
| 帶有后綴通配符* | www.example.* |
- 匹配規(guī)則
優(yōu)先匹配不帶通配符的完整表達(dá)
接著匹配帶有前綴通配符的表達(dá)
最后匹配帶有后綴通配符的表達(dá)
當(dāng)兩個(gè)表達(dá)帶通配符的形式相同的時(shí)候,匹配最長的那個(gè)。
3、location塊詳解
- 語法
location optional_modifier location_match {
...
}
語法中的optional_modifier是描述符,location_match是具體匹配的串形式,如果描述符是正則的一種,那么就會(huì)以正則的方式來對(duì)待location_match,否則以普通方式用location_match來當(dāng)前綴匹配。
- optional_modifier
|類型|含義|匹配方式|優(yōu)先級(jí)|例子|
|:--|:--|:--|:--|
|(none)|最普通的前綴匹配|前綴方式匹配|4|location / {}|
|=|要求絕對(duì)相等|前綴方式匹配|1|location = /image {}|
|~|區(qū)分大小寫的正則匹配|正則方式匹配|3|location ~ .(jpe?g)$ {}|
|~|不區(qū)分大小寫的正則匹配|正則方式匹配|3|location ~ .(jpe?g)$ {}|
|^~|高優(yōu)先級(jí)的前綴匹配|前綴方式匹配|2|location ^~ /page {}|
匹配規(guī)則
最高優(yōu)先級(jí)的是
=,這個(gè)只能完全相等才能匹配上,如果找到符合條件的那么完成匹配。接著在~和(none)中找到一個(gè)能夠匹配出最長串的<sup>1</sup>規(guī)則,如果這個(gè)規(guī)則是屬于~的,那么完成匹配。
否則如果上一步中規(guī)則是屬于(none)的,則還需要給正則表達(dá)式驗(yàn)證一下。這時(shí)候按照location定義的順序一個(gè)一個(gè)地檢測*和規(guī)則,如果發(fā)現(xiàn)一個(gè)滿足的,那么就用這條正則規(guī)則。
最后如果正則規(guī)則中沒有符合條件的,那么就用剛才屬于(none)的規(guī)則,如果剛才連各最長串都沒有,那就跳到默認(rèn)location去了。
注釋1例子
server {
location = /abc {...}
location / {...}
location ^~ /big/middle {...}
location /big/middle/small {...}
location ~ 123+\.jpg {...}
location ~* a+\.jpg {...}
}
如果我們要匹配\big\middle\small的話,是不會(huì)匹配到location ^~ \big\middle {...}這條規(guī)則的,因?yàn)楫?dāng)=規(guī)則匹配結(jié)束沒找到之后,就回去找(none)和^~中匹配最長的一條,這時(shí)候最長的是(none)的location \big\middle\small {...},然后在進(jìn)行正則匹配,發(fā)現(xiàn)沒有滿足的,于是就取(none)的這一條了。這一點(diǎn)要注意。
4、目錄配置
在上述步驟后,我們知道一個(gè)請(qǐng)求具體定位到location的過程,現(xiàn)在來繼續(xù)探究location之后的相應(yīng)處理。首先是location中的資源應(yīng)該對(duì)應(yīng)在哪一個(gè)服務(wù)器目錄中呢?這就需要root屬性來指定了。
root屬性可以定義在server塊中,也可以定義在location塊中。如果聲明在server塊中那么所有的location都會(huì)繼承這個(gè)定義。同時(shí)若location中也定義了root屬性,那么以location中的定義為主。
舉個(gè)例子
server {
...
root /var/www/html
location /cs {
root /share/usr
try_files $uri $uri/ =404;
}
location /eg {
try_files $uri $uri/ =404;
}
}
如果訪問/cs/vr/audio.mp3,那么就會(huì)對(duì)應(yīng)到服務(wù)器上的/share/usr/cs/vr/audio.mp3的資源
如果訪問/eg/file/new.pdf,那么就會(huì)對(duì)應(yīng)到服務(wù)器上的/var/www/html/eg/file/new.pdf的資源
再比如用nginx上架設(shè)codeigniter框架,我們需要重寫url那么我們這樣
server {
listen 80 ;
listen [::]:80;
server_name ci.example.com;
root /var/www/example;
location / {
rewrite ^(.*)$ /index.php?$1 last;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
那么這樣,對(duì)于一個(gè)非.php的文件,都為在第一個(gè)location中重寫成/index.php?$uri的形式重寫進(jìn)行一次搜索。這時(shí)候必然被第二個(gè)location接收(前綴匹配的更長嘛),這樣就完成了codeigniter的定位。
比如我們?cè)L問ci.example.com/hello就會(huì)被重定向到訪問var/www/example/index.php?hello同時(shí)被pass給php的cgi進(jìn)行處理。
參考材料
Understanding Nginx Server and Location Block Selection Algorithms
how-to-configure-nginx