本文介紹如何將NGINX組態作為Web伺服器,並包括以下部分:
在高層次上,將NGINX組態作為Web伺服器有一些問題需要了解,定義它處理哪些URL以及如何處理這些URL上的資源的HTTP請求。 在較低層次上,組態定義了一組控制對特定域或IP地址的請求的處理的虛擬伺服器。
用於HTTP流量的每個虛擬伺服器定義了稱為位置的特殊組態範例,它們控制特定URI集合的處理。 每個位置定義了自己的對映到此位置的請求發生的情況。 NGINX可以完全控制這個過程。 每個位置都可以代理請求或返回一個檔案。 此外,可以修改URI,以便將請求重定向到另一個位置或虛擬伺服器。 此外,可以返回特定的錯誤程式碼,也可以組態特定的頁面以對應於每個錯誤程式碼。
NGINX組態檔案必須至少包含一個伺服器指令來定義虛擬伺服器。 當NGINX處理請求時,它首先選擇提供請求的虛擬伺服器。
虛擬伺服器由http
上下文中的伺服器指令定義,例如:
http {
server {
# Server configuration
}
}
可以將多個server
指令新增到http
上下文中以定義多個虛擬伺服器。server
組態塊通常包括一個listen
指令,用於指定伺服器偵聽請求的IP地址和埠(或Unix域通訊端和路徑)。IPv4和IPv6地址均被接受; 將方括號(。
下面的範例顯示了監聽IP地址127.0.0.1
和埠8080
的伺服器的組態:
server {
listen 127.0.0.1:8080;
# The rest of server configuration
}
如果省略埠,則使用標準埠。 同樣地,如果省略一個地址,伺服器將偵聽所有地址。 如果沒有包含listen指令,則「標準」埠為80/tcp
,「default」埠為8000/tcp
,具體取決於超級使用者許可權。
如果有多個伺服器與請求的IP地址和埠相匹配,則NGINX將根據伺服器塊中的server_name
指令測試請求的主機頭域。 server_name
的引數可以是完整(精確)名稱,萬用字元或正規表示式。 萬用字元是一個字串,其開頭,結尾或兩者都包含星號(*
); 星號匹配任何字元序列。 NGINX將Perl語法用於正規表示式; 在它們之前使用波浪號(?
)。 此範例說明了一個確切的名稱。
server {
listen 80;
server_name example.org www.example.org;
...
}
如果匹配主機頭幾個名稱,則NGINX通過按以下順序搜尋名稱並使用其找到的第一個匹配來選擇一個:
*.example.org
mail.*
如果主機頭欄位與伺服器名稱不匹配,則NGINX會將請求路由到請求到達埠的預設伺服器。 預設伺服器是nginx.conf
檔案中列出的第一個伺服器,除非您將listen_server
引數包含在listen
指令中以明確指定伺服器為預設值。
server {
listen 80 default_server;
...
}
一個完整的Nginx虛擬機器組態範例,這裡我們演示組態兩個虛擬機器,對應域名分別為:vhost1.com
和 vhost2.com
,vhost1.com
網站的主目錄在/data/www/vhost1
,vhost2.com
網站的主目錄在/data/www/vhost2
:
server {
listen 80;
server_name vhost1.com www.vhost1.com;
index index.html index.html;
root /data/www/vhost1;
access_log /var/log/vhost1.com.log;
}
server {
listen 80;
server_name vhost2.com www.vhost2.com;
index index.html index.html;
root /data/www/vhost2;
access_log /var/log/vhost2.com.log;
}
NGINX可以根據請求URI向不同的代理傳送流量或提供不同的檔案。 這些塊是使用放置在server
指令中的location
指令來定義的。
例如,您可以定義三個location
塊,以指示虛擬伺服器向一個代理伺服器傳送一些請求,將其他請求傳送到不同的代理伺服器,並通過從本地檔案系統傳遞檔案來提供其餘請求。
NGINX測試根據所有location
指令的引數請求URI,並應用匹配location
中定義的指令。 在每個location
塊內,通常可能(除了一些例外)放置更多的location
指令以進一步細化特定組請求的處理。
注意:在本教學文章中,單詞
location
是指單個location
上下文。
location
指令有兩種型別的引數:字首字串(路徑名)和正規表示式。 對於要匹配字首字串的請求URI,必須以字首字串開頭。
具有pathname
引數的以下範例位置匹配以/some/path/
開頭的請求URI,例如/some/path/document.html
,它不匹配/my-site/some/path
,因為/some/path
不在該URI的開頭出現。
location /some/path/ {
...
}
正規表示式之前是區分大小寫匹配的波形符號(~
),或者不區分大小寫匹配的波形符號(~*
)。 以下範例將包含字串.html
或.html
的URI與任何位置相匹配。
location ~ \.html? {
...
}
要找到最符合URI的位置,NGINX首先將URI與字首字串的位置進行比較。然後用正規表示式搜尋位置。
除非使用^~
修飾符對正規表示式給予更高的優先順序。在字首字串中,NGINX選擇最具體的字串(也就是最長和最完整的字串)。 下面給出了選擇處理請求的位置的確切邏輯:
=
(等號)修飾符定義了URI和字首字串完全匹配。如果找到完全匹配,則搜尋停止。^~
(插入符號)修飾符預先新增最長匹配字首字串,則不會檢查正規表示式。=
修飾符的典型用例是/
(正斜杠)的請求。 如果請求/
是頻繁的,則指定=/
作為location
指令的引數加速處理,因為搜尋匹配在第一次比較之後停止。
location = / {
...
}
location
上下文可以包含定義如何解析請求的指令 - 提供靜態檔案或將請求傳遞給代理的伺服器。 在以下範例中,匹配第一個location
上下文的請求將從/data/images
目錄中提供檔案,並將匹配第二個位置的請求傳遞給承載 www.example.com
域內容的代理伺服器。
server {
location /images/ {
root /data;
}
location / {
proxy_pass http://www.example.com;
}
}
root
指令指定要在其中搜尋要提供的靜態檔案的檔案系統路徑。 與該位置相關聯的請求URI將附加到路徑,以獲取要提供的靜態檔案的全名。 在上面的範例中,要響應/images/logo.png
的請求,NGINX提供伺服器本地實際對應檔案是:/data/images/logo.png
。
proxy_pass
指令將請求傳遞給使用組態的URL存取代理伺服器。然後將代理伺服器的響應傳回用戶端。在上面的範例中,所有不以/images/
開頭的URI的請求都將被傳遞給代理的伺服器(也就是:www.example.com
)。
可以使用組態檔案中的變數,使NGINX進程的請求根據定義的情況而有所不同。 變數是在執行時計算的命名值,用作指令的引數。 一個變數由它的名字開頭的$
(美元)符號表示。 變數根據NGINX的狀態定義資訊,例如正在處理的請求的屬性。
有許多預定義的變數,如核心HTTP變數,您可以使用set
,map
和geo
指令定義自定義變數。 大多數變數在執行時計算的,並包含與特定請求相關的資訊。 例如,$remote_addr
包含用戶端IP地址,$uri
儲存當前的URI值。
一些網站URI需要立即返回具有特定錯誤或重定向程式碼的響應,例如當頁面被暫時移動或永久移動時。 最簡單的方法是使用return
指令。 例如返回未找到的404
狀態碼:
location /wrong/url {
return 404;
}
返回的第一個引數是響應程式碼。可選的第二個引數可以是重定向的URL(程式碼301
,302
,303
和307
)或在響應體中返回文字。 例如:
location /permanently/moved/url {
return 301 http://www.example.com/moved/here;
}
返回指令可以包含在 location
和 server
上下文中。
可以通過使用rewrite
指令在請求處理期間多次修改請求URI,該指令具有一個可選引數和兩個必需引數。 第一個(必需)引數是請求URI必須匹配的正規表示式。 第二個引數是用於替換匹配URI的URI。 可選的第三個引數是可以停止進一步重寫指令的處理或傳送重定向(程式碼301
或302
)的標誌。例如:
location /users/ {
rewrite ^/users/(.*)$ /show?user=$1 break;
}
如該範例所示,使用者通過匹配正規表示式捕獲第二個引數。
您可以在location
和 server
上下文中包含多個rewrite
指令。 NGINX按照它們發生的順序逐個執行指令。 當選擇該上下文時,server
上下文中的rewrite
指令將被執行一次。
在NGINX處理一組rewrite
指令之後,它根據新的URI選擇一個location
上下文。 如果所選location
塊包含rewrite
指令,則依次執行它們。 如果URI與其中任何一個匹配,則在處理所有定義的rewrite
指令之後,將搜尋新location
塊。
以下範例顯示了與返回指令相結合的rewrite
指令。
server {
...
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;
return 403;
...
}
此範例組態區分兩組URI。 諸如/download/some/media/file
之類的URI更改為/download/some/mp3/file.mp3
。由於最後一個標誌,所以跳過後續指令(第二次rewrite
和return
指令),但NGINX繼續處理該請求,該請求現在具有不同的URI。類似地,諸如/download/some/audio/file
的URI被替換為/download/some/mp3/file.ra
。 如果URI與rewrite
指令不匹配,則NGINX將403
錯誤程式碼返回給用戶端。
有兩個中斷處理重寫指令的引數:
last
- 停止執行當前伺服器或位置上下文中的重寫指令,但是NGINX會搜尋與重寫的URI匹配的位置,並且應用新位置中的任何重寫指令(URI可以再次更改,往下繼續匹配)。break
- 像break
指令一樣,在當前上下文中停止處理重寫指令,並取消搜尋與新URI匹配的位置。新位置(location
)塊中的rewrite
指令不執行。有時您需要重寫或更改HTTP響應中的內容,將一個字串替換為另一個字串。 您可以使用sub_filter
指令來定義要應用的重寫。 該指令支援變數和替代鏈,使更複雜的更改成為可能。
例如,您可以更改參照除代理伺服器之外的絕對連結:
location / {
sub_filter /blog/ /blog-staging/;
sub_filter_once off;
}
另一個範例將方法從http://
更改為http://
,並從請求頭域替換本地主機地址到主機名。 sub_filter_once
指令告訴NGINX在一個位置(location
)內連續應用sub_filter
偽指令:
location / {
sub_filter 'href="http://127.0.0.1:8080/' 'href="http://$host/';
sub_filter 'img src="http://127.0.0.1:8080/' 'img src="http://$host/';
sub_filter_once on;
}
請注意,如果發生另一個sub_filter
匹配,則使用sub_filter
修改的響應部分將不再被替換。
使用error_page
指令,您可以組態NGINX返回自定義頁面以及錯誤程式碼,替換響應中的其他錯誤程式碼,或將瀏覽器重定向到其他URI。 在以下範例中,error_page
指令指定要返回404
頁面錯誤程式碼的頁面(/404.html
)。
error_page 404 /404.html;
請注意,此偽指令並不立即返回該錯誤(返回指令執行該操作),而僅僅是指定發生時如何處理錯誤。 錯誤程式碼可以來自代理伺服器,或者在NGINX處理期間發生(例如,當NGINX找不到用戶端請求的檔案時,顯示404
對應的結果)。
在以下範例中,當NGINX找不到頁面時,它會將程式碼301
替換為程式碼404
,並將用戶端重定向到http:/example.com/new/path.html
。 當用戶端仍嘗試存取其舊URI的頁面時,此組態非常有用。 301
程式碼通知瀏覽器頁面已經永久移動,並且需要在返回時自動替換舊地址。
location /old/path.html {
error_page 404 =301 http:/example.com/new/path.html;
}
以下組態是在未找到檔案時將請求傳遞給後端的範例。 因為在error_page
指令的等號之後沒有指定狀態程式碼,所以對客戶機的響應具有代理伺服器返回的狀態程式碼(不一定是404
)。
server {
...
location /images/ {
# Set the root directory to search for the file
root /data/www;
# Disable logging of errors related to file existence
open_file_cache_errors off;
# Make an internal redirect if the file is not found
error_page 404 = /fetch$uri;
}
location /fetch/ {
proxy_pass http://backend/;
}
}
當沒有找到檔案時,error_page
指令指示NGINX進行內部重定向。 error_page
指令的最終引數中的$uri
變數儲存當前請求的URI,該URI在重定向中被傳遞。
例如,如果沒有找到/images/some/file
,它將被替換為/fetch/images/some/file
,並且新的搜尋位置(location
)開始。最後請求最終在第二個location
上下文中,並被代理到http://backend/
。
如果沒有找到檔案,則open_file_cache_errors指令可防止寫入錯誤訊息。 因為丟失的檔案可被正確地處理,但這不是必需的。