正向代理和反向代理的概念
代理服務(Proxy),通常也稱為正向代理服務。
如果把局域網外Internet想象成一個巨大的資源庫,那么資源就分布到了Internet的各個點上,局域網內的客戶端要訪問這個庫里的資源就必須統一通過代理服務器才能對各個站點進行訪問。
局域網內的機器借助代理服務訪問局域網外的網站, 這主要是為了增加局域網內部網絡的安全性,使得網外的威脅因素不容易影響到網內,這里代理服務器起到了一部分防火牆的功能。同時,利用代理服務器也可以對局域網外的訪問進行必要的監控和管理。正向代理服務器不支持外部對內部網絡的訪問請求。
與正向代理服務相反,如果局域網向Internet提供資源,讓Internet上的其他用戶可以訪問局域網內的資源,也可以設置一個代理服務器,它提供的服務就叫做反向代理(Reverse Proxy)服務。可以看到,反向代理服務與代理服務在功能邏輯上剛好是相反的。
正向代理服務器與反向代理服務器的概念很簡單,歸納起來就是,正向代理服務器用來讓局域網客戶機接入外網以訪問外網資源,反向代理服務器用來讓外網的客戶端接入局域網中的站點以訪問站點中的資源。理解這兩個概念的關鍵是要明白我們當前的角色和目的是什么,在正向代理服務器中,我們的角色是客戶端,目的是要訪問外網的資源;在反向代理服務器中,我們的角色是站點,目的是把站點的資源發布出去讓其他客戶端能夠訪問。
知道了這兩個概念,就可以學習如何讓Nginx服務器來提供代理和反向代理服務器了。
Nginx的正向代理服務
Nginx服務器正向代理服務的配置的3個指令
在實際應用中,使用Nginx服務器代理服務功能的情況相對少一些,Nginx代理服務本向也相對簡單,涉及的主要指令不多。這些指令原則上可以出現在Nginx配置文件的http塊、server塊或者location塊中,但一般是在搭建的Nginx服務器中單獨配置一個server塊用來設置代理服務。
1.resolver指令
該指令用於指定DNS服務器的IP地址。DNS服務器的主要工作是進行域名的解析,將域名映射為對應的IP地址。該指令的語法結構為:
resolver address ... [valid=time];
address,DNS服務器的IP地址。如果不指定商品號,默認使用53端口。
time,設置數據包在網絡中的有效時間。出現該指令的主要原因是,在訪問站點時,有很多情況使得數據包在一定時間內不能被傳遞到目的地,但是又不能讓該數據包無期限地存在,於是就需要設定一段時間,當數據包在這段時間內沒有到達目的地,就會被丟棄,然后發送都會接收到一個消息,並決定是否要重發數據包。
使用該指令的一個例子如下:
resolver 127.0.0.1 [::1}:5353 valid=30s
在實際應用中,一般不需要設置這么復雜,只要將DNS服務器的IP地址設置給該指令即可。
從Nginx1.1.7版本開始,該指令支持設置多個IP地址,從Nginx1.3.1開發版本和Nginx1.2.2穩定版本開始,該指令支持設置IPV6地址。
2.resolver_timeount指令
resolver_timeount time;
該指令用於設置DNS服務器域名解析超時時間,語法結果為:
3.proxy_pass指令
該指令用於設置代理服務器的協議和地址,它不僅僅用於Nginx服務器的代理服務器,更主要的是應用於反向代理服務,我們馬上就會談及。該指令的語法結構為:
proxy_pass URL;
其中,URL即為設置的代理服務器協議和地址。
在代理服務配置中,該指令的設置相對固定,因此在這里就不介紹其他細節了,具體內容在學習Nginx服務器的反向代理服務時再重點闡述。在代理服務配置中,該指令配置為:
proxy_pass http://$http_host$request_uri;
其中,代理服務器協議設置為HTTP,$http_host和$request_uri兩個變量是Nginx配置支持的用於自動獲取主機和URI的變量。配置代理服務時,一般不要改變該指令的配置。
正向代理服務使用示例
.. server { resolver 8.8.8.8; listen 82; location / { proxy_pass http://$http_host$request_uri; } }
實現的片段很簡單,設置DNS服務器地址為8.8.8.8,使用默認的53號端口作為DNS服務器的服務端口,代理服務的監聽端口設置為82端口,Nginx服務器接收到的所有請求都由第5行的location塊進行過濾處理。
Nginx服務器代理服務使用的場合不多,從上一節的配置指令來看,功能也相對簡單。在使用過程中,有一些需要注意的事項在這里說明一下。
首先,我們在上面提到過,設置Nginx服務器的代理服務器,一般是配置到一個server塊中,注意,在該server塊中,不要出現 server_name指令,即不要設置虛擬主機的名稱或IP。而resolver指令是必需的,如果沒有該指令,Nginx服務器無法處理接收到的域名。
其次,Nginx服務器的代理服務器不支持正向代理HTTPS站點。
Nginx的反向代理服務
Nginx服務器的反向代理服務是其最常用的重要功能之一,在實際工作中應用廣泛,涉及的配置指令也比較多,各類指令完成的功能也不盡相同。下面按照功能分類向大家介紹配置該服務需要掌握的指令。由反向代理服務又可以衍生出多種與此相關的Nginx服務器的重要功能,隨后將逐步梳理這些功能,並提供配置實例供大家參考。
Nginx服務器提供的反向代理服務也是比較高效的。它能夠同時接收的客戶端連接由worker_processes指令和worker_connections指令決定,計算方法為:worker_processes * worker_connections / 4.
配置Nginx服務器反向代理用到的指令如果沒有特別說明,原則上可以出現在Nginx配置文件的http塊、server塊或者location塊中,但同正向代理服務的設置一樣,一般是在搭建的Nginx服務器中單獨配置一個server塊來設置反射代理服務。這些指令主要由ngx_http_proxy_module模塊進行解析和處理。該模塊是Nginx服務器的標准HTTP模塊。
反向代理的基本設置的27個指令
學習Nginx服務器的反向代理 服務,要涉及與后端代理服務器相關的配置,是客戶端提供正常Web服務的基礎,大家應該熟練掌握,尤其是proxy_pass指令,在實際應用過程中需要注意一些配置細節,需要小心使用。
1.proxy_pass指令
該指令用來設置被代理服務器的地址,可以是主機名稱、IP地址加端口號等形式。其語法結構為:
proxy_pass URL;
其中,URL為要設置的被代理服務器的地址,包含傳輸協議、主機名稱或IP地址加商品號、URI等要素。傳輸協議通常是“http”或者“https”。指令同時還接受以“unix”開始的UNIX-domain套接字路徑。例如:
proxy_pass http://www.myweb.name/uri; proxy_pass http://localhost/uri; proxy_pass http://unix:/tmp/backend.socket:/uri/;
如果被代理服務器是一組服務器的話,可以使用upstream指令配置后端服務器組。例如:
#多個服務器 ... upstream proxy_svrs #配置后端服務器 { server http://192.168.1.1:8001/uri/; server http://192.168.1.2:8001/uri/; server http://192.168.1.3:8001/uri/; } server { ... listen 80; server_name www.myweb.name; location / { proxy_pass proxy_svrs; #使用服務器組名稱 } }
這里首先需要提醒大家proxy_pass指令在使用服務器組名稱時應該注意一個細節。在上例中,在組內的各個服務器中都指明了傳輸協議“http://”,而在proxy_pass指令中就不需要指明了。如果 現在將upstream指令的配置改為:
#不指明http ... upstream proxy_svrs #配置后端服務器 { server 192.168.1.1:8001/uri/; server 192.168.1.2:8001/uri/; server 192.168.1.3:8001/uri/; }
我們就需要在proxy_pass指令中指明傳輸協議“http://”;
proxy_pass http://proxy_svrs;
在使用該指令的過程中還需要注意,URL中是否包含有URI,Nginx服務器的處理方式是不同的。如果URL中不包含URI,Nginx服務器不會改變原地址的URI;但是如果包含了URI,Nginx服務器將會使用新的URI替代原來的URI。我們舉例來說明。
請看下面的Nginx配置片段:
.. server { ... server_name www.myweb.name; resolver 8.8.8.8; listen 82; location /server/ { ... proxy_pass http://192.168.1.1; } }
如果客戶端使用“http://www.myweb.name/server ”發起請求,該請求被配置中顯示的location塊進行處理,由於proxy_pass指令變量不含有URI,所以轉向的地址為“http:///192.168.1.1/server ”;我們再來看下面的Nginx片段:
.. server { ... server_name www.myweb.name; resolver 8.8.8.8; listen 82; location /server/ { ... proxy_pass http://192.168.1.1/loc; } }
在該配置實例中,proxy_pass指令的URI包含了URI“/loc”;如果客戶端仍然使用“http://www.myweb.name/server ”發起請求,Nginx服務器將會把地址轉向“http://192.168.1.1/loc/ ”;
通過上面的實例,我們可以總結 出,在使用proxy_pass指令時,如果不想改變原地址中的URI,就不要在URL變量中配置URI。
明白了上面這兩個例子的用法,我們來解釋大家經常討論的一個問題,就是proxy_pass指令的URL變量末尾是否加斜杠“/”的問題。
請看這兩個配置示例:
#配置1 proxy_pass http://192.168.1.1; #配置2 proxy_pass http://192.168.1.1/;
配置1和配置2的區別在於,配置2中的proxy_pass指令的URL變量末尾添加了斜杠“/”,這意味着配置2中的proxy_pass指令的URL變量包含了URI“/”,而配置1中的proxy_pass指令的URL變量不包含URI。理解了這一點,我們就可以解釋下面的實例和現象了。大家注意各例子之間的對比。
實例1:
.. server { ... listen 80; server_name www.myweb.name; #注意location的uri變量 location / { ... #配置1 proxy_pass http://192.168.1.1; #配置2 proxy_pass http://192.168.1.1/; } }
在該配置中,location塊使用“/”作為uri變量的值來匹配不包含URI的請求URL。由於請求URL中不包含URL,因此配置1和配置2的效果是一樣的。比如客戶端的請求URL為“http://www.myweb.name/index.htm”,其將會被實例1中的location塊匹配成功並進行處理。不管使用配置1不是配置2,轉向的URL都為:“http://192.168.1.1/index.htm”。
實例2:
.. server { ... listen 80; server_name www.myweb.name; #注意location的uri變量 location /server/ { ... #配置1 proxy_pass http://192.168.1.1; #配置2 proxy_pass http://192.168.1.1/; } }
在該配置中,location塊使用“/server/”作為uri變量的值來匹配包含的URI“/server/”的請求URL。這時,使用配置1和配置2的轉向結果就不相同了。使用配置1和配置2的轉向效果就不相同了。使用配置1時候,proxy_pass指令中的URL變量不包含URI,Nginx服務器將不改變原地址的URI,使用配置2的時候,proxy_pass指令中的URL變量包含URI“/”,Nginx服務器會將原地址的URI替換為"/"。
比如客戶端的請求URI為“http://www.myweb.name/server/index.htm”將會被實例2的location塊匹配成功並進行處理。使用配置1的時候,轉向的URL為“http://192.168.1.1/server/index.htm”,原地址的URI“、server/”示被改變;使用配置2時,轉向的URL為“http://192.168.1.1/index.htm”,可以看到原地址的URI“/server/”被替換為“/”。
大家在應用過程中,一定要注意到該指令在配置上的細節問題,分清楚URL和URI的區別與聯系,並能夠正確使用它們配置出符合需求的Nginx服務器。
2.proxy_hide_header指令
該指令用於設置Nginx服務器在發送HTTP響應時,隱藏一些頭域信息。其語法結構為:
proxy_hide_header field;
其中,field為需要隱藏的頭域。該指令可以在http塊、server塊或者location塊中進行配置。
3.proxy_pass_header指令
默認情況下,Nginx服務器在發送響應報文時,報文頭中不包含“Date”、“Server”、“X-Accel”等來自被代理服務器的頭域信息。該指令可以設置這些頭域信息以被發送,其語法結構為:
proxy_pass_header field;
4.proxy_pass_request_body指令
該指令用於配置是否將客戶端請求的請求體發送給代理服務器,其語法結構為:
proxy_pass_request_body on | off;
默認開啟(on),開頭可以在http塊、server塊或者location塊中進行配置。
5.proxy_pass_request_headers指令
該指令用於配置是否將客戶端請求的請求頭發送給代理服務器,其語法結構為:
proxy_pass_request_headers on | off;
默認開啟(on),開頭可以在http塊、server塊或者location塊中進行配置。
6.proxy_set_header指令
該指令可以理發Nginx服務器接收到的客戶端請求的請求頭信息,然后將新的請求頭發送給被代理的服務器,其語法結構為:
proxy_set_header field value;
field,要更新的信息所在的區域;value,更改的值,支持使用文本、變量或者變量的組合。
默認情況下,該指令的設置為:
proxy_set_header Host $proxy_host; proxy_set_header Connection close;
請看一些設置實例:
proxy_set_header Host $http_host; #將目前Host頭域的值填充成客戶端的地址 proxy_set_header Host $$host; #將當前location塊的server_name指令填充到Host頭域 proxy_set_header Host $$host:$proxy_port; #listener指令值一起填充到Host頭域.
7.proxy_set_body指令
指該指令可以更改Nginx服務器接收到的客戶端請求的請求信息,然后將新的請求體發送給被代理的服務器。其語法結構為:
proxy_set_body_value;
其中,value為更改的信息,支持使用文本、變量或者變量的組合。
8.proxy_bind指令
官方文檔中對該指令的解釋是,強制將與代理主機的連接綁定到指定的IP地址。通俗來講就是,在配置多個基於名稱或者基於IP地址。通俗來講就是,在配置了多個基於名稱或者基於IP主機的情況下,如果我們希望代理連接由指定的主機處理,就可以使用該指令進行配置,其語法結構為:
proxy_bind adress;
其中,adress為指定主機的IP地址。
9.proxy_connect_timeout指令
該指令配置Nginx服務器與后端被代理服務器嘗試建立連接的超時時間,其語法結構為:
proxy_connect_timeout time;
其中,time為設置的超時時間,默認60s。
10.proxy_read_timeout指令
該指令配置Nginx服務器向后端被代理服務器(組)發出的read請求后,等待響應的超時時間,其語法結構為:
proxy_read_timeout time;
其中,time為設置的超時時間,默認60s。
11.proxy_send_timeout指令
該指令配置Nginx服務器向后端被代理服務器(組)發出的write請求后,等待響應的超時時間,其語法結構為:
proxy_write_timeount time
其中,time為設置的超時時間,默認60s。
12.proxy_http_version指令
該指令設置用於Nginx服務器提供代理服務的HTTP協議版本,其語法結構為:
proxy_http_version 1.0 | 1.1;
默認版本為1.0版本,1.1版本支持upstream服務器組設置的keepalive指令。
13.proxy_method指令
該指令用於設置Nginx服務器請求被代理服務器時使用的請求方法,一般為POST或者GET。設置了該指令,客戶端的請求方法將被忽略。其語法結構為:
proxy_method method;
其中,method的值可以設置為POST或者GET,注意不加引號。
14.proxy_ignore_client_abort指令
該指令用過設置在客戶端中斷網絡請求時,Nginx服務器是否中斷對被代理服務器的請求,其語法結構為:
proxy_ignore_client_abort on | off
默認設置為off,當客戶端中斷網絡請求時,Nginx服務器中斷對被代理服務器的請求。
15.proxy_ignore_header指令
該指令用於設置一些HTTP響應頭的頭域,Nginx服務器接收到被代理服務器的響應數據后,不會處理被設置的頭域。其語法結構為:
proxy_ignore_header field ...;
其中,field為要設置的HTTP響應頭的頭域,例如“X-Accel-Redirect”、“X-Accel-Expires”、“Cache-Control”、“Expires”或“Set-Cookie”等。
16.proxy_redirect指令
該指令用於修改被代理服務器返回的響應頭中的Location頭域和“Refresh”頭域,與proxy_pass指令配合使用。比如,Nginx服務器通過proxy_pass指令將客戶端的請求地址重寫為被代理服務器的地址,那么Nginx服務器返回客戶端的響應頭中“Location”頭域顯示的地址就應該和客戶端發起請求的地址相對應,而不是代理服務器直接返回的地址信息,否則就會出問題。該指令解決了這個問題,可以把代理服務器返回的地址信息更改為需要的地址信息。其語法結構為:
proxy_redirect redirect replacement proxy_redirect default; proxy_redirect off;
redirect,匹配“Location”頭域值的字符串,支持變量的使用和正則表達式。
replacement,用於替換redirect變量內容的字符串,支持變量的使用。
該指令的用法我們通過幾個配置實例來解釋。
對於第1個結構,假設被代理服務器返回的響應頭中的“Location”頭域為:
Location: http://localhost:8081/proxy/some/uri
該指令設置為:
proxy_redirect http://localhost:8081/proxy/ http://myweb/fronted/;
Nginx服務器會將“Location”頭域信息更改為:
Location:http://myweb/frontend//some/uri;
這樣,客戶端收到的響應信息頭部中的“Location”頭域就被更改了。
結構 2使用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/; }
使用結構3可以將當前作用域下所有的proxy_redirect指令全部設置為無效。
17.proxy_intercept_errors指令
該指令用於配置一個狀態是否開啟還是關閉。在開啟狀態時,如果被代理的服務器返回的HTTP狀態碼為400或者大於400,則Nginx服務器使用自己定義的錯誤頁(使用error_page指令);如果是關閉狀態,Nginx服務器直接將被代理服務器返回的HTTP狀態返回給客戶端。其請求結構為
proxy_intercept_errors on | off
18.proxy_headers_hash_max_size指令
該指令用於配置HTTP報文頭哈希表的容量,其語法結構為:
proxy_headers_hash_max_size size;
其中,size為HTTP報文頭哈希表的容量上限,默認為512個字符,即:
proxy_headers_hash_max_size 512;
Nginx服務器為了能夠快速檢索HTTP報文頭中的各項信息,比如服務器名稱、MIME類型、請求頭名等,使用哈希表存儲這些信息。Nginx服務器在申請存放HTTP報文頭的空間時,通常以固定大小為單位申請,該大小由proxy_headers_hash_bucket_size指令配置。
在Nignx配置中,不僅能夠配置整個哈希表的大小上限,對大部分內容項,也可以配置其大小上限,比如server_names_hash_max_size指令和server_names_hash_bucket_size指令用來設置服務器名稱的字符數長度。
19.proxy_headers_hash_bucket_size指令
該指令用於設置Nginx服務器申請存放HTTP報文頭的哈希表容量的單位大小。該指令的具體作用在上面proxy_headers_bucket_size指令的使用中已經說明。其語法結構為:
proxy_headers_hash_bucket_size size;
20.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,無法將請求發送給被代理的服務器。
注意
與被代理的服務器進行數據傳輸的過程中發送錯誤的請求,不包含在該指令支持的狀態之內。
21.proxy_ssl_session_reuse指令
該指令用於配置是否使用基於SSL安全協議的會話連接(“https://”)被代理的服務器,其語法結構為:
proxy_ssl_session_reuse on | off