nginx服務器的反向代理時其最常用的重要功能之一,在實際工作中應用廣泛,涉及的配置指令也比較多。下面會盡量詳細地介紹對應的指令,及其使用狀態。
反向代理一般是互聯網需要向內網拉取資源,比如訪問一個web網站時,互聯網應用通過一個代理服務器到后面真實的web服務器拉取應用所需的數據。
nginx服務器反向代理用到的指令如果沒有特別的說明,原則上可以出現在nginx配置文件的http塊,server塊和location塊中,但是同正向代理一樣,一般是搭建在nginx服務器中單獨配置一個server塊用來設置代理服務。這些指令主要由ngx_http_proxy_module模塊進行解析和處理。該模塊是nginx服務器的標准http模塊。
nginx服務器支持設置一組服務器作為后端服務器,因此在說明nginx反向代理指令之前,首先說明nginx的后端服務器組的配置。
后端服務器組的指令,是由nginx標准模塊ngx_http_upstream_module進行解析和處理的。
后端服務器組的指令
1.upstream指令,該指令是設置后端服務器組的主要指令,其他指令都在該指令中進行配置。語法結構為
upstream name {
...... #后端服務器設置
}
#其中name是后端服務器的組名。花括號中列出了后端服務器組中包含的服務器。
默認情況下,某個服務器組接收到請求后,按照輪叫調度策略順序選擇組內的服務器處理請求。如果一個服務器在處理請求過程中出現錯誤,則請求會被順序交給組內的下一個服務器處理,一直到返回正常響應。但是如果所有組內的服務器出錯,則返回最后一個服務器的處理結果。還可以在根據每個服務器的處理能力不同,給各個服務器配置不同的權重。權重的配置包含在server指令中。
2:server指令
該指令用於設置組內的服務器,語法結構為
server address [parameters];
#address: 服務器的地址,可以是包含端口號的ip地址,域名或者以“unix:”為前綴的用於進程間通信的套接字
#parameters: 為當前服務器的更多屬性,如下。
- weight=number, 為組內的服務器設置權重,權重高的被優先用於請求處理。默認服務器權重為1.
- max_fails=number, 設置請求失敗次數。在一定時間范圍內,當對組內某台服務器請求失敗的次數超過該變量設置的值時,認為該服務器無效。默認是1,
若設置為0則不用上面的辦法檢查服務器是否有效、
- fial_timeout=time;有兩個作用,一個是 設置 max_fails指令中“一定時間范圍”的時長,二是在檢查服務器是否有效時,如果一台服務器被認為是無效的,
該變量設置的時間為認為服務器無效持續的時間。在這個時間內不再檢查該服務器的狀態,並一直認為它是無效的。默認是10s。
- backup: 將組內服務器標記為備用服務器,只有當正常的服務器處於無效(down)狀態或者繁忙(busy)狀態時,該服務器才被用來處理客戶請求。
- down:將某台服務器標記為永久無效狀態。
3: ip_hash指令,該指令用於實現會話保持功能,將某個客戶端的多次請求定向到組內同一台服務器上,保證客戶端與服務器之間建立穩定的會話。只有當該服務器無效處於down狀態時,客戶端請求才會被下一個服務器接收和處理。
ip_hash;
ip_hash技術在一些情況下非常有用,能夠避免我們關心的服務組內各個服務器之間會話共享的問題。但是ip_hash技術在應用過程中是有限制的。
首先,ip_hash指令不能與server指令中的weight變量一起使用。其次,由於ip_hash技術主要根據客戶端的ip地址分配服務器,因此整個系統中,nginx服務器應該是處於最
前端的服務器,這樣才能獲取到客戶端的ip地址,同時還要注意客戶端的ip地址必須是C類地址。
upstream backend
{
ip_hash;
server www.test1.com;
server www.test2.com;
}
如上一個實例,在添加ip_hash指令后,使用同一台服務器發送請求,將會看到一只是test1在響應;如果注釋掉ip_hash,將會看到的是輪詢響應請求。
4.keepalive指令,該指令用於控制網絡連接保持功能。通過該指令,能夠保證nginx服務器工作進程為服務器組打開一部分網絡連接,並且將數量控制在一定范圍內。類似於進程池。
keepalive connections;
#connections為nginx1服務器每一個工作進程運行服務器組保持的空閑網絡連接數的上限值。如果超過該值,工作進程將采用最近最少使用策略關閉網絡連接、
5:least_conn指令,該指令用於配置nginx服務器使用負載均衡的策略。該指令在功能上實現了最少連接負載均衡算法,在選擇組內的服務器時,考慮個服務器權重的同時,每次選擇的都是當前連接最少的那台服務器,如果這樣的服務器有多台,則選用加權輪叫原則選擇權重最大的服務器。
least_conn;
反向代理指令
nginx的反向代理指令有很多,這里我們會詳細的介紹的!
1.proxy_pass指令,該指令用來設置被代理服務器的地址,可以是主機名稱,IP地址加端口號的形式。
proxy_padd URL;
#其中,URL為要設置的被代理服務器的地址,包含傳輸協議,主機名稱或IP地址加端口號,uri等,傳輸協議通常是http或者https。也可以是unix開頭的套接字路徑。
若是被代理的是一組服務器,則需要使用upstream指令配置后端服務器組!
通過簡單的實例說明proxy_pass的用法!
#第一種僅代理一個服務器 location / { proxy_pass http://10.0.102.214:8080; }
#第二種,代理一組服務器 upstream backend #需要注意的是upstream指令不能寫在server塊中 { server 10.0.102.214:8080; server 10.0.102.204:8080; } server { listen 80; server_name localhost; location / { proxy_pass http://backend; } }
##############################################
說明,之前有一種寫法是把http協議寫在upstream中,這樣在proxy_pass中不用寫http協議,但是我現在這樣的寫的話,檢查的時候總是會報錯!
upstream backend
{
server http://10.0.102.214:8080;
server http://10.0.102.204:8080;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass backend;
}
}
#這樣配置的時候總是會報錯,
[root@test1 conf]# nginx -t
nginx: [emerg] invalid host in upstream "http://10.0.102.214:8080" in /usr/local/nginx/conf/nginx.conf:37
nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed
proxy_pass中url是否包含URI的處理方式:如果URL中包含了URI,nginx服務器會使用新的uri替代原來請求中的URI;如果URL中不包含URI,nginx服務器不會改變原地址請求的URI。
#URL中包含了URI的配置
location /first.html { root html; index index.html index.htm; proxy_pass http://10.0.102.214:8080/one.html; } ##看這個配置,URL中含有URI,那么nginx服務器會改變原來請求中的URI!
[root@test1 logs]# curl http://localhost/first.html #訪問本機
111111111111111111
[root@test1 logs]# curl http://10.0.102.214:8080/one.html #后面代理服務器的one.html
111111111111111111
#上面兩個可以看到,通過代理訪問時,uri被nginx服務器改寫了!
#URL不包含URI的配置
location /first.html {
root html;
index index.html index.htm;
proxy_pass http://10.0.102.214:8080;
}
#可以看到如果URL中不含URI,則nginx服務器不會改寫請求中的URI。
[root@test1 logs]# curl http://localhost/first.html
This is the first page!
[root@test1 logs]# curl http://10.0.102.214:8080/first.html
This is the first page
2.proxy_hide_header與proxy_pass_hide
默認情況下,nginx服務器在發送響應報文時候,報文頭部不包含如“Date”,"Server","X-Accel"等來自被代理服務器的信息,但是也會發送一些與被代理服務器有關的信息。
proxy_hide_header field;
#指令用於設置nginx服務器發送響應時,隱藏一些頭部信息。
proxy_pass_header;
#該指令可以設置哪些頭部信息被發送
上面的兩個指令均可在http塊,server塊或者location塊中進行配置
默認情況下,代理服務器不會發送后端服務器的server信息給客戶端,這里我們設置代理服務器發送后端服務器的server信息給客戶端!
#當前做代理服務器的nginx版本為 [root@test1 logs]# nginx -v nginx version: nginx/1.10.2 [root@test1 logs]# #后端服務器的nginx版本為 [root@test3 html]# nginx -v nginx version: nginx/1.0.15 [root@test3 html]#
配置如下:
proxy_pass_header server; #設置要發送的信息 location /first.html { root html; index index.html index.htm; proxy_pass http://10.0.102.214:8080; }
#訪問對應的URL
[root@mgt01 ~]# curl http://10.0.102.179/first.html -I
HTTP/1.1 200 OK
Date: Sun, 16 Dec 2018 16:03:02 GMT
Content-Type: text/html
Content-Length: 24
Connection: keep-alive
Server: nginx/1.0.15 #可以看到發送的nginx服務器的版本為后端服務器的版本信息
Last-Modified: Sun, 16 Dec 2018 15:39:16 GMT
Accept-Ranges: bytes
#把配置文件中proxy_pass_header server; 注釋掉,訪問信息如下:
[root@mgt01 ~]# curl http://10.0.102.179/first.html -I
HTTP/1.1 200 OK
Server: nginx/1.10.2 #這里的版本信息為代理服務器的版本信息
Date: Sun, 16 Dec 2018 16:07:41 GMT
Content-Type: text/html
Content-Length: 24
Connection: keep-alive
Last-Modified: Sun, 16 Dec 2018 15:39:16 GMT
Accept-Ranges: bytes
3.proxy_pass_request_body與proxy_pass_request_headers指令
這兩個指令用於配置是否將客戶端請求的請求體和請求頭發送給后端服務器,語法結構如下:
proxy_pass_request_body on | off; proxy_pass_request_header on | off;
#默認設置為開啟。
4:proxy_set_header指令,該指令可以更改nginx服務器接收到客戶端請求的請求頭消息,然后將新的請求頭發送給后端服務器。
proxy_set_header field value;
#field: 要更改的頭域
#value: 更改的值,支持文本,變量或者變量的組合
默認情況下,nginx 重新定義代理請求Host
和Connection
中的兩個頭字段,並刪除了值為空字符串的頭字段。其中請求頭Host
被設置為了變量$proxy_host
,Connection
被設定為close
。
proxy_set_header Host $http_host; #將目前的host值填充為客戶端請求的host
proxy_set_header Host $proxy_host; #將當前location塊的server_name填充到host頭域。
proxy_set_header Host $host:$$proxy_port; #將當前location塊的server_name指令和listen指令值一起填充到host頭域
5:proxy_set_body指令
該指令可以更改nginx服務器接收到客戶端請求的請求體的信息,然后將新的請求體發送給后端服務器。
proxy_set_body value;
#value為更改的信息,支持使用文本,變量或者變量的組合。
6:proxy_bind指令。在配置了多個基於名稱或者基於ip主機的情況下,如果我們希望代理連接由指定的主機處理,就可以使用該指令進行配置。
proxy_bind address;
#address為指定主機的ip地址。
7:proxy_connect_timeout指令
該指令配置nginx服務器以后端服務器嘗試建立連接的時間,
proxy_connect_timeout time;
#time為設置的超時時間,默認是60s
8:proxy_read_timeout指令
該指令配置nginx服務器向后端被代理服務器發出read請求后,等待響應的超時時間。
proxy_read_timeout time;
#time為設置的超時時間,默認是60s
9:proxy_send_timeout指令
該指令配置nginx服務器向后端被代理服務器發出write請求后,等待響應的超時時間,
proxy_send_timeout time;
#time為設置的超時時間,默認是60s
10:proxy_http_version指令
該指令用於配置nginx服務器提供代理服務的http版本,
proxy_http_version 1.0|1.1;
#默認是1.0版本。1.1版本支持upstream服務器組設置中的keepalive指令。
11.proxy_method指令
該指令用於設置nginx把請求發往后端服務器組時使用的請求方法,一般為POST或者GET。設置了該指令,客戶端的請求方法將被忽略。
proxy_method method;
#其中,method的值可以設置為POST或者GET,注意不加引號。
12:proxy_ignore_client_abort指令
該指令用於設置在客戶端中斷網絡請求時,nginx服務器是否中斷對后端服務器的請求。
proxy_ignore_client_abort on|off;
#默認設置為off,當客戶端中斷網絡請求時,nginx服務器中斷對后端服務器的請求
13:proxy_ignore_headers指令
該指令用於設置一些http響應頭域,nginx服務器接收到被代理服務器的響應數據后,不會處理被設置的頭域。
proxy_ignore_headers field....;
#field為要設置的http響應頭,
14:proxy_redirect指令
該指令用於修改后端服務器返回的響應頭中的location頭域和refresh頭域,與proxy_pass指令配合使用。比如,nginx服務器通過proxy_pass指令將客戶端的請求地址重寫為被代理服務器的地址,那么nginx服務器返回給客戶端的響應頭中“location”頭域顯示的地址就應該和客戶端發起請求的地址相對應,而不是代理服務器直接返回的地址信息,否則就會出現問題。該指令解決了這個問題,可以把代理服務器返回的地址信息更改為需要的地址信息,語法結構如下!
1 proxy_redirect redirect replacement; 2 proxy_redirect default; 3 proxy_redireect off; #表示當前作用於下所有的proxy_redirect指令配置全部設置為無效。 #redirect,匹配“Location”頭域值的字符串,支持變量的使用和正則表達式 #replacement, 用於替換redirect變量內容的字符串,支持變量的引用。
通過兩個實例,來理解這個命令!【摘自nginx高性能web服務器詳解】
第一個例子
假設被代理服務器返回的響應頭中“location”頭域為
Location: http://localhost/proxy/some/uri
該指令設置為:
proxy_pass http://localhost/proxy/ http://x.x.x.x/fromtend/;
nginx服務器會將“Location”頭域信息更改為:
Location: http://x.x.x.x/fromtend/some/uri
這樣客戶端收到的響應信息頭部中的“Location”頭域已經被更改。注意還是為安全,把后端服務器的信息暴露出來是不安全的!
第二個例子
使用default,代理使用Location塊的uri變量作為replacement,並使用proxy_pass變量為redirect。下面的兩個配置結果是相等的。
#配置1 location /server/ { proxy_pass http://proxyserver/source/; proxy_redirect default; } #配置2 location /server/ { proxy_pass http://proxyserver/source/; proxy_redirect http://proxyserver/source/ /server/; } #配置1和配置2產生的結果是一樣的
15:proxy_intercept_errors指令
該指令用於配置一個狀態是開啟還是關閉。在開啟狀態時,如果后端服務器返回的http狀態碼為400或者大於400,則nginx服務器使用自己定義的錯誤頁(使用error_pages指令);如果關閉了該狀態,nginx服務器直接將后端服務器返回的http狀態返回給客戶端。
proxy_intercept_errors on | off;
16:proxy_headers_hash_max_size指令
該指令用於配置存放http報文頭的哈希表的容量,語法結構為
proxy_headers_hash_max_size size;
#size為http報頭哈希表容量上限,默認為512個字符。
nginx服務器為了能夠快速檢索http報文頭中的各項信息,比如服務器名稱,MIME類型,請求頭名稱,使用哈希表存儲這些信息。nginx服務器在申請存放http報文頭空間時,通常以固定大小為單位申請,該大小由此指令設定。
在nginx配置中,不僅能夠配置整個哈希表的上限,對於大部分內容,也可以配置其大小的上限。比如server_names_hash_max_size指令server_names_hash_bucket_size指令用來設置服務器名稱的字符數長度。
17:proxy_headers_hash_bucket_szie指令
該指令用於設置nginx服務器申請存放http報文的哈希表容量的單位大小,具體使用見上一個命令。
proxy_headers_hash_bucket_szie size;
#size為設置容量,默認為64個字符
18:proxy_next_upstream指令
在配置nginx服務器反向代理時,如果使用了upstream指令配置了一組服務器作為被代理服務器,服務器組中各個服務器的訪問規則遵循upstream指令配置的輪詢規則,同時也可以使用該指令配置在發生哪些異常情況下,將請求順序交由下一個組內服務器處理。
proxy_next_upstream status...;
status為設置的服務器返回的狀態,可以是一個或者多個。狀態取值如下:
- error,在建立連接,向后端服務器發送請求,讀取響應頭時服務器發生連接錯誤。
- timeout, 在建立連接,向后端服務器發送請求,讀取響應頭時服務器發生連接超時。
- invalid_header, 后端服務器返回的響應頭為空或者無效。
- http_500|http_502|http_503|http_504|http_404,后端服務器返回500,502,503,504,404狀態碼。
- off,無法將請求發送到后端服務器。
19:proxy_ssl_session_reuse指令
該指令用於配置是否使用基於ssl安全協議的會話連接被代理的服務器。
proxy_ssl_session_reuse on|off;
默認設置為開啟狀態。
我們通過實例來說明nginx反向代理的用法:
第一個實例,對所有的請求實現一般輪詢的負載均衡
upstream backend { server 10.0.102.214:8080; server 10.0.102.204:8080; } server { listen 80; server_name localhost; root html; index index.html index.htm; location / { proxy_pass_header server; proxy_pass http://backend; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
#默認情況下,后端服務器組中每台服務器的權重值為1,使用輪叫調度的策略。
第二個實例,對所有的請求實現加權輪叫調度
配置就是把上面后端服務器組中每台服務器后面加上權重即可!
upstream backend { server 10.0.102.214:8080 weight=1; server 10.0.102.204:8080 weight=2; } server { listen 80; server_name localhost; root html; index index.html index.htm; location / { proxy_pass_header server; proxy_pass http://backend; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
#權重高的服務器優先處理請求和響應,所有的請求都會在backend服務器組中實現加權負載均衡。
第三個實例,對不同資源實現負載均衡,這里定義兩組后端服務器組,對圖片的訪問和對文件的訪問使用不同的服務器組,這樣就可以對不同資源做負載均衡!
#定義兩個服務器組,分別對文件和圖片進行處理
upstream file_backend #定義文件服務器組 { server 10.0.102.220; server 10.0.102.221; } upstream image_backend #定義圖片服務器組 { server 10.0.102.214; server 10.0.102.204; } server { listen 80; server_name localhost; root html; index index.html index.htm; location /files/ { #針對文件訪問,使用下面的服務器組 proxy_pass_header server; proxy_pass http://file_backend/files/; } location /images/ { #針對圖片的訪問使用下面的服務器組,, proxy_pass http://image_backend/images/; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
第四種情況,針對不同的域名做負載均衡。
在配置文件中可以配置多個server塊,每個塊都是一個虛擬主機,每個塊中根據server_name的不同,被轉發到后端不同的服務器上。
upstream bbs_backend { server 10.0.102.214; server 10.0.102.204; } upstream home_backend { server 10.0.102.214; server 10.0.102.204; } server { #根據不同的域名,訪問到不同的服務器組 listen 80; server_name www.bbs.com; index index.html index.htm; location / { proxy_pass http://bbs_backend; } } server { listen 81; server_name www.home.com; index index.html index.htm; location / { proxy_pass http://home_backend; } }