1. 程式人生 > >Nginx之反向代理配置(一)

Nginx之反向代理配置(一)

  前文我們聊了下Nginx作為web伺服器配置https、日誌模組的常用配置、rewrite模組重寫使用者請求的url,回顧請參考https://www.cnblogs.com/qiuhom-1874/p/12398242.html;今天來聊一聊Nginx是怎麼反向代理,怎麼防盜鏈;前文的最後我們提到了防盜鏈,到底什麼是防盜鏈呢?在我們平時上網相信很多人都遇到過這樣的情況,我們開啟一個網頁,在裡面可以看到很多裂圖,看不到圖片,或者看到此圖片僅某某網站網友交流使用之類的,這就是防盜鏈;我們知道在一個網頁裡面,裡面的資源不一定都是來自一個伺服器的,比如圖片很可能來自圖片伺服器,js、css很可能來自其他靜態資源伺服器上;所以稍微懂點的人就知道如何將別人網站上的圖片、js檔案呀連結到自己的網站使用,這種行為就叫盜用別人家的資源,簡稱盜鏈;這裡就不過多闡述了;我們來說說nginx的referer模組吧。

  一、ngx_http_referer_module:此模組用於阻止對“Referer”頭欄位中包含無效值的請求的站點訪問;

  通常一次http事務就是客戶端請求服務端,服務端響應客戶端的一個流程;客戶端請求服務端,會在請求頭部新增一些資訊,比如用什麼方法請求服務端的資源呀,資源的路徑是什麼,用的http協議版本是多少,請求的host主機上什麼等等;其中如果客戶端是直接從瀏覽器上介入域名直接訪問web伺服器,其頭部是沒有referer這個資訊的;referer是什麼?referer是記錄客戶端從哪裡來訪問我們客戶端的,如果客戶端是通過某個網站點選訪問到我們的伺服器時,它發過來的請求頭部就有對應網站的域名;防盜鏈就是利用referer這個頭部的資訊來做控制的;

  1、valid_referers none | blocked | server_names | string ...;定義合法referer合法值;這裡解釋下,none表示請求頭部沒有referer欄位,通常情況下沒有referer欄位都是從瀏覽器(web客戶端)介入域名訪問的;blocked表示請求頭部有referer欄位,但是沒有值,像這種請求我們是無法判斷客戶端是從哪裡訪問我們伺服器的,通常情況我們把這類請求時允許訪問的;server_name表示請求頭部有referer欄位和資訊,其值就是對方主機名;我們在定義一個合法的referer時,是可以用通配或正則去匹配server_name;

  示例:

valid_referers none blocked server_names
               *.example.com example.* www.example.org/galleries/
               ~\.google\.;

  提示:以上配置表示合法的referer有 ,請求報文裡沒有referer欄位的請求,有referer欄位但是沒有值的,以任何內容開頭結尾是.example.com的主機名或者是以example開頭的主機,或者referer是www.example.org/galleries/或者是包含google的都是合法的,意思是客戶端請求報文的referer資訊滿足我們定義的合法資訊,或者說能夠被我們定義的合法referer匹配到,我們就說該使用者是一個合法的請求,理所當然的是應該允許被訪問的;當然我們定義了合法referer,如果客戶端請求報文裡的referer資訊不配我們定義的合法referer匹配,我們就說這裡客戶端的referer是非法的,是不被允許的,理所當然的就應該做其他處理;這個是ngxin裡內部的機制,不被合法referer所匹配的referer都是非法的referer,通常是用$invalid_referer保留這些不合法referer;或者我們這樣理解,不被合法referer所匹配的請求報文就會被$invalid_referer所匹配;有了這種機制我們就可以明確定義那些請求時合法的,相對的那些請求是不合法的,對於不合法的我們可以這麼處理;如下

   提示:以上配置表示如果客戶端請求報文的referer資訊不是.ilinux.com結尾或者不是以www.ilinux.開頭 或者 不是www.ilinux.io 或者不包含.baidu.或者.google. 我們都響應該客戶端請求響應碼為403;

  二、ngx_http_proxy_module:此模組允許將請求傳遞到另一個伺服器。

  1、proxy_pass URL;該指令主要作用是用來設定被代理伺服器地址的,可以說主機名稱,IP地址加埠的形式;其中URL表示被代理伺服器的地址,包含協議、主機名或IP加埠、URI等。傳輸協議通常是“http”或者"https";如果我們被代理的是一個本地unix-domain套接字時,也支援以http://或https://加unix套接字路徑的形式;如果我們代理的是一組伺服器時,我們可以用upstream指令把該組伺服器同一歸併為一個名稱的組伺服器組,當然這是我們後面要聊的nginx作為負載均衡的配置;這裡特別要說明的是URL中是否包含URI,什麼意思呢,就是URL不包含URI的意思就是 被代理的URL沒有URI,就只有協議IP地址或域名或主機名,這種就叫不帶URI;帶URI就表示除了協議主機名或域名或IP地址外,後面還有RUI;對於這兩種情況Nginx處理邏輯上不一樣的,如果RUL不包含URI 那麼nginx伺服器不會改變源地址的URI;如果URL包含URI,nginx伺服器將會使用新的URI替換原來的URI;

  示例:

   提示:以上配置就是我們所的URL不包含URI的情況,使用者請求www.test.com/en/docs/將會被該location匹配到,然後將訪問www.test.com/en/docs/將會被代理到http://nginx.org/en/docs/;我們可以理解為被代理的URL不包含URI時,Nginx伺服器會把使用者請求的URI當作被代理伺服器的URI;所以以上配置就表示,使用者訪問www.test.com/en/docs/將被代理至http://nginx.org/en/docs/

  提示:在做以上實驗時,需要在Windows上做好解析www.test.com;Windows上需要在C:\Windows\System32\drivers\etc\hosts檔案中新增一條解析記錄,語法同Linux裡的hosts一樣192.168.0.30 www.ilinux.io www.test.com;

   提示:以上配置就是URL包含URI的情況,這種情況Nginx伺服器會把使用者請求的URI替換成被代理的URI;以上面的配置示例,如果使用者請求www.test.com/test/那麼這個請求到了nginx伺服器時,nginx會把使用者原有的URI/test/替換成/en/docs/,所以使用者請求www.test.com/test/就會被代理至http://nginx.org/en/docs/;

  提示:通過上面的演示,我們可以總結為,如果我們不想改變源請求的URI,那麼我們在後端代理時就不帶URI,如果我們想更改源請求URI,那麼我們在後端代理時,就帶上URI即可

  理解了上面我們所的URL包含或不包含URI,我們就不難理解下面的例子

  示例:proxy_pass URL末尾是否帶“/”問題

   提示:以上配置和我們之前的第一個示例就只多了一個“/”;多一個“/”在我們看來是不要緊,但它對nginx來說,意思卻變了,就以我們上面說的,這種就是URL包含URI的情況,nginx會把後面的“/”認為是URI,不是認為,它本來就是一個URI;當客戶端請求www.test.com/en/docs/時,nginx會把該請求代理至http://nginx.org/;當然這樣處理後的結果肯定和我們之前的結果是完全不一樣的,http://nginx.org/就表示請求nginx.org的主頁;

  提示:和第一個示例一樣的URL,對於proxy_pass URL後面沒有"/"和有“/”被代理響應的結果是不一樣的;

  除了上面URL包含或不包含URI問題需要我們特別注意外,我們還要注意,如果location定義URI時使用了正則,或在if語句或在limit_execept中使用了proxy_pass指令,則proxy_pass 之後不能使用URI;使用者請求時傳遞的URI將直接附加代理到的伺服器之後;意思就是URL包含URI的情況不能在location 使用了正則匹配URL,或者URL包含URI的情況不允許用在if語句中  或limit_except中

  示例:

   提示:這種配置我們在語法檢查的時候就通不過,要想被通過,我們只需要把proxy_pass指令後面的URI去掉即可

   提示:總結一點就是location中使用了正則匹配 URL時,後面代理是不能有URI的,否則語法錯誤;

   2、proxy_set_header field value;設定發往後端主機的請求報文的請求首部的值;可用在http,server,location配置段中

proxy_set_header X-Real-IP  $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  提示:以上配置表示在使用者請求通過代理髮送給後端主機時,在其請求頭部加上X-Real-IP這個欄位,並且這個欄位的值是$remote_addr(客戶端IP地址)和X-Forwarded-For欄位,其值為$proxy_add_x_forwarded_for;$proxy_add_x_forwarded_for 這個變數是也是記錄IP地址的,不同的是,這個變數它記錄了客戶端IP和代理服務端ip,兩個IP分別用逗號隔開,如果沒有代理伺服器的場景,這個變數的意義同$remote_addr是一樣的,都是記錄客戶端客戶端IP

  3、proxy_cache_path:定義可用於proxy功能的快取,此指令只可配置在http配置段;

  語法:

    proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];

    path:表示設定快取資料存放路徑,該路徑必須事先存在;

    levels;表示設定存放快取資料的目錄級別,這個和前面說的nginx快取目錄一樣。levels=1:2表示兩級目錄,且一級目錄是一個字元雜湊目錄,二級目錄是兩個字元的雜湊目錄,目錄名稱是基於URL雜湊演算法獲取到的;

    keys_zone=name:size 表示設定快取索引在記憶體區域的名稱和大小;

    inactive=time設定非活動快取時間,在指定的時間內如果該快取項沒有被命中,nginx就會強制把該快取從磁碟上刪除,如果下次有人訪問時在快取,依次迴圈;預設10分鐘;

    max_size=size:設定磁碟中快取資料的大小限制,當快取資料超過我們設定的大小時,就是用LRU演算法來刪除快取;

    loader_files=number:設定快取索引重建程序每次載入的資料元素的數量上限;

    loader_sleep=time:設定快取索引重建程序在一次遍歷結束、下次遍歷開始之間的暫停時長,預設是50ms

    loader_threshold=time:設定遍歷一次磁碟快取源資料的時間上限,預設設定為200ms

  通常情況下我們不需要設定這麼多選項,只需要把前三個選項設定好就行了,沒有特殊的要求後面的選項我們用預設值就可以

  示例:

   提示:以上配置表示定義代理快取路徑是/cache/proxy/nginx 目錄級別是1:2:1  快取索引重建程序記憶體區域名稱為proxy_cache,大小為10M 對於磁碟上的/cache/proxy/nginx/目錄最大快取空間為2g;這樣設定後,我們就可以在各個server或location中來呼叫此快取定義

  4、proxy_cache zone | off;指明要呼叫的快取,或關閉快取機制;此指令可用於http,server,location配置段中;

  示例

   提示:這樣去呼叫快取空間進行快取是不能夠快取的,因為我們呼叫快取空間是有條件的,比如我們要對那些請求方法的請求進行快取?對不同響應碼的資源快取多久?是否在後端伺服器出現錯誤時,我們繼續使用快取來響應?所以我們現在雖然配置了呼叫快取空間,但是我們伺服器還是不知道怎麼去快取客戶訪問的內容;所以它乾脆就不給快取;

  示例:我們只調用了快取空間,沒有配置其他配置,使用者訪問的資料是否能夠快取下來呢?

  提示:可以看到我們只配置快取空間然後呼叫是不行的,我們還需要指定快取的key是什麼 ,對客戶端使用的那些方法進行快取,對不同的響應碼的資源快取多久,這是呼叫快取空間的幾個必要的配置,我們需要加上才行;

  5、proxy_cache_key:定義快取key,預設是$scheme$proxy_host$request_uri,它這個預設就是快取的key是協議加代理主機地址或主機名或FQDN和使用者請求的uri當作快取的KEY;也就是說服務端怎麼去找快取的方式,對應key的定義;

  6、proxy_cache_methods METHODS:定義快取使用者的請求方式,也就是說那些請求方法的資源我們要進行快取,預設是GET HEAD;

  7、proxy_cache_valid [code] time:定義不同的響應碼的資源快取時長;

  8、proxy_cache_use_stale error |timeout|……:定義後端伺服器基於那種狀態使用快取,預設是不基於後端伺服器狀態使用快取;比如後端伺服器發生錯誤,是否用快取中的內容響應客戶端?如果我們定義 proxy_cache_use_stale http 403就表示後端伺服器如果響應代理伺服器403,我們代理伺服器就是用之前的快取,響應客戶端;

  示例:

   提示:以上配置表示使用proxy_cache快取空間,快取key是使用者請求的uri進行快取,對使用者使用GET 和HEAD方法請求的資源進行快取,對響應碼是200 302的資源快取15分鐘,對響應碼是404的資源快取1分鐘,後端伺服器出現500 或502的錯誤,代理伺服器使用以前的快取響應客戶端;

   提示:可看到瀏覽器請求了兩個uri,在對應的快取目錄裡就存在兩個快取項;這裡面每一個快取項就是對應一個使用者請求過多URI;通常情況我們啟用了Nginx代理快取功能時,使用者第一次訪問就會很慢,但是隻要把資料快取下來後,後續的使用者在訪問相同的URI時,這個速度就會有明顯的提升;

   總結對於nginx的快取,我們首先在http配置段定義一個快取空間,然後在各server或location中呼叫我們定義的快取空間,並明確說明各種響應碼的資源快取多長時間,對於proxy_cache_key 和 proxy_cache_methods是可以不指定的,不指定就代表使用預設值,從上面的配置我們其實就只定義響應碼是多少的資源快取多久,其他的按照預設來,它也是可以進行快取