apache httpd反向代理的用法


代理方式有三種:正向代理、透明代理和反向代理

正向代理                      

httpd通過ProxyRequests指令配置正向代理的功能。例如:

ProxyRequests On
ProxyVia On

<Proxy "*">
  Require host internal.example.com
</Proxy>

其中< Proxy >容器表示的是只有internal.example.com下的主機可以通過該正向代理去訪問任意URL的請求內容。ProxyVia指令表示在響應首部中添加一個Via字段。

反向代理                      

為了成為一個"基本的"web server,提供靜態和動態內容給最終用戶,httpd(以及其他大多數web server)可以扮演反向代理服務器的角色,也就是眾所周知的"網關"服務器。

在這種場景下,Httpd自身不生成產出數據,而是從后端服務器中獲取數據,這些后端服務器器一般不會和外界網絡通信。當httpd從客戶端接收到請求,請求被代理到后端服務器組中的其中一個服務器上,該后端服務器處理請求,生成內容並返回內容給httpd server,最后由httpd server生成實際的HTTP響應給客戶端。

有無數應該使用反向代理的理由,最常見的是安全、高可用、負載均衡、集中授權/認證。反向代理的布置和架構中,后端服務器(真正處理請求的服務器)和外界完全絕緣並由此受到保護,對於外界客戶端來說,當他們需要關心服務器對象是誰時,它們得到的結果總是反向代理服務器,而非后端服務器。

一個典型的實現如下:

 

簡單的反向代理配置                          

ProxyPass指令用於映射請求到后端服務器。最簡單的代理示例是對所有請求"/"都映射到一個后端服務器上:

ProxyPass "/"  "http://www.example.com/"
ProxyPassMatch "^/((?i).*\.php)$" "fcgi://127.0.0.1:9000/var/www/a.com/$1"

為了地址重定向時也能正確使用反向代理,應該使用ProxyPassReverse指令,該指令的作用見下文。

ProxyPass "/"  "http://www.example.com/"
ProxyPassReverse "/"  "http://www.example.com/"

或者只為特定的URI進行代理,例如下面的配置,只有/images開頭的路徑才會代理轉發,其他的所有請求都在本地處理。

ProxyPass "/images"  "http://www.example.com/"
ProxyPassReverse "/images"  "http://www.example.com/"

假如本地服務器地址為http://www1.example.com,當請求http://www1.example.com/images/a.gif時,將代理為http://www.example.com/a.gif

在沒有重定向的情況下,ProxyPassReverse是可以省略的,否則一般情況下應該將其設置為和ProxyPass相同。ProxyPassReverse提供的是一種功能,它並不依賴於ProxyPass(但一般都同時存在)。它的作用是防止重定向時客戶端無法正確訪問。例如,http://www.example.com/images/a.gif被代理為http://192.168.100.17/a.gif,如果此時a.gif被重定向到b.gif,那么代理服務器返回給客戶端的將是http://192.168.100.17/b.gif。但客戶端是無法訪問后端內網主機192.168.100.17的,於是出現file not found錯誤。如果此時使用ProxyPassReverse,那么代理服務器響應給客戶端的請求會被調整為http://www.example.com/images/b.gif,這樣的請求再發給代理服務器,就能正確訪問。

負載均衡:后端成員                        

上面的配置中沒有添加后端服務器節點,無法享受反向代理的優點。因此,有必要添加后端節點。添加的方法是使用< proxy >容器將后端節點定義成一個負載均衡組,各節點是該組中成員,然后代理目標指向組名即可。

例如:

 

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080
    ProxySet lbmethod=bytraffic
</Proxy>

ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

 

alancer://myset告訴httpd,它創建了一個負載均衡節點集合,名稱為myset,此集合中有兩個后端成員。在上面的配置中,任意/images的請求都會代理至2個成員中的一個。ProxySet指令指定myset均衡組使用的均衡算法為bytraffic,即基於I/O流量字節數權重的算法。ProxySet指令設置的是Proxy容器的公共屬性

httpd有3種負載均衡算法:

  • byrequests:默認。基於請求數量計算權重。
  • bytraffic:基於I/O流量大小計算權重。
  • bybusyness:基於掛起的請求(排隊暫未處理)數量計算權重。

對於上面的示例,還可以稍加修改,使其支持更多功能。例如添加權重比例,使得某后端節點被轉發到的權重是另一節點的3倍,等待后端節點返回數據的超時時間為1秒。

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyPass "/images"  "balancer://myset/"
ProxyPassReverse "/images"  "balancer://myset/"

故障轉移                              

還可以再次調整實現故障轉移,例如當所有負載節點都失敗時,指定一個備份節點(standby node)。參考如下配置:

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    BalancerMember http://hstandby.example.com:8080 status=+H
    BalancerMember http://bkup1.example.com:8080 lbset=1
    BalancerMember http://bkup2.example.com:8080 lbset=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

其中成員1、2、4、5是負載節點,成員3是備份節點。當所有負載節點都不健康時,將轉發請求給備份節點,並由備份節點處理請求,httpd設置備份節點的方式很簡單,只需將狀態設置為"H",表示hot-standby。還需注意的是負載節點4、5,它們額外的參數為lbset=1,不寫時默認為0,這是負載均衡時的優先級設置,負載均衡時總是先轉發給低數值的節點,也就是說數值越小,優先級越高。所以上面的配置中,當節點1、2正常工作時,只在它們之間進行負載,此時節點4、5處於閑置狀態。只有當節點1、2都失敗時,才會在節點4、5之間進行負載。

提供負載狀態顯示頁面                        

<Location "/bm">
    SetHandler balancer-manager
    Require host localhost
    Require ip 192.168.100
</Location>

然后在瀏覽器中輸入http://server/bm即可,返回結果如圖。

proxy相關指令                      

ProxyPass指令                              

該指令將遠程服務器映射到本地主機上,但本地主機不是真實的服務器,而是遠程主機的一個鏡像。這個鏡像通常稱為反向代理服務器或網關。該指令不能用於< Directory >、< Files >容器中,且使用該指令時通常會關閉正向代理,即ProxyRequests=off

語法:

ProxyPass [path] !|url [key=value [key=value ...]]

path參數為本地主機的URL路徑,url參數為遠程服務器的url一部分,不能包含查詢參數。如果第一個參數path尾隨了斜線,則url部分也必須尾隨斜線,反之亦然。如果該指令封裝在< Location >容器中,則第一個參數path可以省略,因為Location中已經指定了URL路徑。如果第二個參數為"!",則表示此path不使用反向代理功能。

<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/foo/"
</Location>

當訪問http://server/mirror/foo/bar時,將轉發到http://backend.example.com主機上,並請求該主機的/foo/bar文件。下面的配置指令與此等價。

ProxyPass "/mirror/foo/" "http://backend.example.com/foo/"

如果想讓某個子目錄不進行反向代理,而是在本地處理。可以設置第二個參數為"!"。例如,下面的配置中,/mirror/foo會被代理,但/mirror/foo/i則不會被代理。

ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"

再需要說明的是連接池,httpd會為后端節點創建連接池,httpd會連接連接池中的各個節點。后端節點屬性相同的共享一個連接池。后端節點的屬性由key=value參數指定。以下是常見的一些屬性設置,完整的屬性見官方手冊

  • keepalive=Off|On:默認為Off。設置httpd和后端節點之間是否開啟長連接,注意,這和web服務的長連接不一樣,此處設置的是反向代理服務器和后端節點兩者連接,當httpd將請求轉發給連接池中的一個節點,並等待返回數據,當數據返回完成后,連接立即關閉,如果開啟了長連接,連接暫時不關閉,只有等待均衡算法下次輪到該節點時才會再使用該連接。通常只有在httpd和后端節點間使用了防火牆時才設置為On。
  • lbset=N:默認為0。設置后端節點的優先級。數值N越低的,優先級越高。httpd總是會先嘗試優先級高的,只有優先級高的節點不可用時,才一會嘗試優先級低的。
  • ping=N:默認為0。設置和ajp13協議(不支持http協議)通信時健康狀況檢查時間間隔。該ping只能檢查是否能ping通對方,也就是檢測是否能與對方通信。單位為秒,可以帶上后綴"ms"表示毫秒。更多的健康狀況檢查應該使用mod_proxy_hcheck模塊。
  • retry=N:默認為60秒。當檢測到后端某節點錯誤狀態(error status)時,將在每N秒后才轉發一次請求給該節點。設置為0表示正常轉發請求,不用任何等待時間。該屬性通常設置用來維護服務器下線然后再上線的情況。
  • status=VALUE:將節點手動置為何種狀態。包括以下幾種狀態,各狀態可使用"+"(默認)來賦予屬性,使用"-"來取消屬性。例如"+H","S-E"。

    • D: 該節點被禁用,不再接受任何請求。
    • S: 該節點處於管理維護的目的被停止。
    • I: 將該節點設置為無視錯誤(ignore-errors)模式,此模式下httpd將認為該節點可用,總會轉發請求給該節點。
    • H: 該節點處於hot-standby模式,該節點只有在其他所有后端節點都失效時才啟用。因此,該節點為備份節點。
    • E: 將該節點設置為錯誤狀態(error-state)。
    • N: 將該節點設置為drain模式,該模式只接受已預定粘滯會話的請求sticky session,其他所有請求都會被忽略。
  • timeout=ProxyTimeout:設置httpd等待后端節點返回數據的超時時間。

如果使用了"balancer://",例如前面的balancer://myset,將創建一個虛擬的連接池。虛擬連接池中的各節點可共享部分屬性,也可以為每個節點設置上面所說的屬性。共享屬性使用ProxySet指令設置,常見的包括下面幾種:

  • lbmethod=METHOD:設置負載均衡算法。有三種:byrequests(默認)按照請求數量計算均衡節點;bytraffic按照io流量計算均衡節點;bybusyness按照繁忙程度計算計算均衡節點。
  • nofailover=On|Off:默認為off。session不可用時是否轉移到其他具有相同session的節點上。如果后端節點不支持session復制,應將此項設置為on。
  • stickysession:設置session粘滯的名稱,如JSESSIONID、PHPSESSIONID。

例如:

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    BalancerMember http://hstandby.example.com:8080 status=+H
    BalancerMember http://bkup1.example.com:8080 lbset=1
    BalancerMember http://bkup2.example.com:8080 lbset=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyRequests off
ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

ProxyPassMatch指令                            

正則匹配模式的ProxyPass。例如:

ProxyPassMatch "^/(.*\.gif)$" "http://backend.example.com/$1"
ProxyPassMatch "^/((?i).*\.php)$" "fcgi://127.0.0.1:9000/var/www/a.com/$1"

唯一需要注意的是,在正則匹配之前,遠程url參數必須是能夠解析的URL地址。例如下面兩條指令,第一條指令將失敗,因為在正則解析前,url參數無法解析為正確的URL地址,這是一個bug,可以通過修改正則表達式的分組部分將"/"分離出去,正如下面的第二個指令。

ProxyPassMatch "^(/.*\.gif)$" "http://backend.example.com:8000$1"
ProxyPassMatch "^/(.*\.gif)$" "http://backend.example.com:8000/$1"

ProxySet指令                                

設置Proxy后端節點的屬性。通常用來設置共享屬性,但也可以設置某一個節點的屬性。

例如:

<Proxy "balancer://hotcluster">
    BalancerMember "http://www2.example.com:8080" loadfactor=1
    BalancerMember "http://www3.example.com:8080" loadfactor=2
    ProxySet lbmethod=bytraffic
</Proxy>
<Proxy "http://backend">
    ProxySet keepalive=On
</Proxy>
ProxySet "balancer://foo" lbmethod=bytraffic timeout=15

< Proxy >容器                                  

< Proxy >容器用於封裝一組proxy相關指令,這些指令主要用於設置訪問權限、負載均衡成員組以及它們的屬性。

例如,下面的設置了只有yournetwork.example.com下的主機才能通過該(正向或反向代理)服務器訪問任意請求的內容(使用了*進行通配)。

<Proxy "*">
  Require host yournetwork.example.com
</Proxy>
<Proxy "balancer://hotcluster">
    BalancerMember "http://www2.example.com:8080" loadfactor=1
    BalancerMember "http://www3.example.com:8080" loadfactor=2
    ProxySet lbmethod=bytraffic
</Proxy>

ProxyStatus指令                                  

ProxyStatus {on|off|full}決定是否開啟server-status中關於proxy的狀態信息,默認為off,full是on的同義詞。

例如

ProxyStatus on
<Location "/server-status">
        SetHandler server-status
        Require all granted
</Location>

以下是關於proxy相關的狀態示例:

----------------------------------------------------------------------

                 Proxy LoadBalancer Status for balancer://myset

   SSes Timeout Method     
   -    0       byrequests 

   Sch  Host           Stat         Route Redir F Set Acc Wr Rd 
   http 192.168.100.14 Init Ok                  1 0   0   0  0  
   http 192.168.100.15 Init Ok                  3 0   0   0  0  
   http 192.168.100.54 Init Stby Ok             1 0   0   0  0  
   http 192.168.100.16 Init Ok                  1 1   0   0  0  
   http 192.168.100.21 Init Ok                  3 1   0   0  0  

     ----------------------------------------------------------------------

   SSes    Sticky session name         
   Timeout Balancer Timeout            
   Sch     Connection scheme           
   Host    Backend Hostname            
   Stat    Worker status               
   Route   Session Route               
   Redir   Session Route Redirection   
   F       Load Balancer Factor        
   Acc     Number of uses              
   Wr      Number of bytes transferred 
   Rd      Number of bytes read

ProxyVia指令                              

是否在響應首部中添加"Via:"字段。可以設置為On/Off等。例如如設置為On時:

 

[root@xuexi ~]# curl -I http://192.168.100.17/index.html
HTTP/1.1 200 OK
Date: Sun, 01 Oct 2017 18:10:17 GMT
Server: Apache/2.4.27 (Unix)
Last-Modified: Sun, 01 Oct 2017 14:10:48 GMT
ETag: "29-55a7cd31f2329"
Accept-Ranges: bytes
Content-Length: 41
Content-Type: text/html; charset=UTF-8
Via: 1.1 customer.sharktech.net

 

ProxyPass指令的排序和共享問題                          

ProxyPass指令有個需要注意的問題,在匹配生效時,最先被匹配到的指令立即生效,后面的都將失效。但如果ProxyPass指令放在< Location >容器中時,由於容器中只能放置一個ProxyPass指令(因為path參數一樣),此時匹配越精確的越優先。

例如下面的指令,如果將兩個ProxyPass指令位置調換,則/mirror/foo/i也仍會被代理。

ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"

可以將它們分別定義到< Location >容器中,這樣就無需考慮位置順序,而是考慮匹配的精確程度,因為Location容器自身有加載順序優先級。例如,下面的配置是可行的。

<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/"
</Location>
<Location "/mirror/foo/i">
    ProxyPass "!"
</Location>

還需考慮一個共享的問題。下面兩個指令中的url參數各有長短,且第一個url是第二個url的子串。這時第二個ProxyPass的屬性部分總是會使用第一個指令的屬性。因此/examples/bar的請求被轉發到backend.example.com/examples/bar時,它的屬性timeout=60而非10。這樣的屬性共享可以減少創建連接池,相對來說更有效一些。

ProxyPass "/apps" "http://backend.example.com/" timeout=60
ProxyPass "/examples" "http://backend.example.com/examples" timeout=10

健康狀況檢查模塊                

ProxyPass指令自帶了ping屬性,可用於簡單判斷后端節點是否健康,只要Ping能通信就認為是健康的。但顯然,對於Http服務來說,健康的指標並不能簡單地通過它來判斷。例如,檢測某個頁面是否正常、是否允許某方法等。因此,httpd提供了一個專門的健康狀況檢查模塊mod_proxy_hcheck用於個性化訂制檢查指標。

檢查指標也即檢查方法有以下幾種,由hcmethod指定:

  • TCP:檢查是否能與后端節點建立TCP套接字,這就是問對方"你還活着嗎"。
  • OPTIONS:發送一個HTTP OPTIONS請求給后端節點。
  • HEAD:發送一個HTTP HEAD請求給后端節點。
  • GET:發送一個HTTP GET請求給后端節點。

該健康狀況檢查模塊認為,只要HTTP方法的檢查指標返回2xx或3xx狀態碼都認為是健康的。

指定了檢查方法后,還需訂制檢查的細節,例如檢查的時間間隔。包括以下幾項:

  • hcinterval:默認為30秒。發送檢查的時間間隔,單位為秒。
  • hcuri:健康檢查時,追加在URL后的URI。通常用於GET檢查方法。
  • hcpasses:默認為1。表示只有檢查了N次后都是通過的,才認為該節點是健康的可再次啟用。
  • hcfails:默認為1。表示只有檢查了N次后都是失敗的,才認為該節點已經不健康,於是禁止使用該節點。

例如,以下是幾個健康檢查的配置示例:

<Proxy balancer://foo>
  BalancerMember http://www.example.com/  hcmethod=GET hcuri=/status.php
  BalancerMember http://www1.example.com/ hcmethod=TCP hcinterval=5 hcpasses=2 hcfails=3
  BalancerMember http://www2.example.com/
</Proxy>

ProxyPass "/" "balancer://foo"
ProxyPassReverse "/" "balancer://foo"


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM