1. 程式人生 > >nginx反向代理-後端伺服器組設定

nginx反向代理-後端伺服器組設定

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;
        }
}

#這樣配置的時候總是會報錯,
[[email protected] 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!
[[email protected] logs]# curl http://localhost/first.html #訪問本機
111111111111111111
[[email protected] 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。
[[email protected] logs]# curl http://localhost/first.html
This is the first page!
[[email protected] 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版本為
[[email protected] logs]# nginx -v
nginx version: nginx/1.10.2
[[email protected] logs]# 
#後端伺服器的nginx版本為
[[email protected] html]# nginx -v
nginx version: nginx/1.0.15
[[email protected] html]# 

配置如下:

        proxy_pass_header server;             #設定要傳送的資訊
        location /first.html {
            root   html;
            index  index.html index.htm;
            proxy_pass http://10.0.102.214:8080;
        }

#訪問對應的URL
[[email protected] ~]# 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; 註釋掉,訪問資訊如下
[[email protected] ~]# 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 重新定義代理請求HostConnection中的兩個頭欄位,並刪除了值為空字串的頭欄位。其中請求頭Host被設定為了變數$proxy_hostConnection被設定為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;
        }
    }