详细分析 apache httpd 反向代理的用法
代理方式有兩種:正向代理和反向代理。
正向代理是為客戶端轉(zhuǎn)發(fā)請求,各客戶端將請求交給正向代理服務(wù)器,正向代理服務(wù)器再負(fù)責(zé)轉(zhuǎn)發(fā)給服務(wù)端,響應(yīng)時服務(wù)端先響應(yīng)給正向代理服務(wù)器,正向代理服務(wù)器再轉(zhuǎn)發(fā)給對應(yīng)的客戶端。也就是說,正向代理是為局域網(wǎng)內(nèi)客戶端做代理,它扮演的角色類似于 NAT。
反向代理是為服務(wù)端轉(zhuǎn)發(fā)請求,客戶端將請求發(fā)送至反向代理服務(wù)器,反向代理服務(wù)器再將請求轉(zhuǎn)發(fā)給真正的服務(wù)器以處理請求,響應(yīng)時后端真正的服務(wù)器將處理結(jié)果發(fā)送給反向代理,再由反向代理構(gòu)建響應(yīng)并響應(yīng)給客戶端。
httpd 通過 ProxyRequests 指令配置正向代理的功能。例如:
ProxyRequests On
ProxyVia On
<Proxy "*">
Require host internal.example.com
</Proxy>
其中 <Proxy> 容器表示的是只有 internal.example.com 下的主機(jī)可以通過該正向代理去訪問任意 URL 的請求內(nèi)容。ProxyVia 指令表示在響應(yīng)首部中添加一個 Via 字段。
為了成為一個 "基本的"web server,提供靜態(tài)和動態(tài)內(nèi)容給最終用戶,httpd(以及其他大多數(shù) web server) 可以扮演反向代理服務(wù)器的角色,也就是眾所周知的 "網(wǎng)關(guān)" 服務(wù)器。
在這種場景下,Httpd 自身不生成產(chǎn)出數(shù)據(jù),而是從后端服務(wù)器中獲取數(shù)據(jù),這些后端服務(wù)器器一般不會和外界網(wǎng)絡(luò)通信。當(dāng) httpd 從客戶端接收到請求,請求被代理到后端服務(wù)器組中的其中一個服務(wù)器上,該后端服務(wù)器處理請求,生成內(nèi)容并返回內(nèi)容給 httpd server,最后由 httpd server 生成實際的 HTTP 響應(yīng)給客戶端。
有無數(shù)應(yīng)該使用反向代理的理由,最常見的是安全、高可用、負(fù)載均衡、集中授權(quán) / 認(rèn)證。反向代理的布置和架構(gòu)中,后端服務(wù)器 (真正處理請求的服務(wù)器) 和外界完全絕緣并由此受到保護(hù),對于外界客戶端來說,當(dāng)他們需要關(guān)心服務(wù)器對象是誰時,它們得到的結(jié)果總是反向代理服務(wù)器,而非后端服務(wù)器。
一個典型的實現(xiàn)如下:
2.1 簡單的反向代理配置
ProxyPass 指令用于映射請求到后端服務(wù)器。最簡單的代理示例是對所有請求 "/" 都映射到一個后端服務(wù)器上:
ProxyPass "/" "http://www.example.com/"
ProxyPassMatch "^/((?i).*.php)$" "fcgi://127.0.0.1:9000/var/www/a.com/$1"
為了地址重定向時也能正確使用反向代理,應(yīng)該使用 ProxyPa***everse 指令,該指令的作用見下文。
ProxyPass "/" "http://www.example.com/"
ProxyPa***everse "/" "http://www.example.com/"
或者只為特定的 URI 進(jìn)行代理,例如下面的配置,只有 / images 開頭的路徑才會代理轉(zhuǎn)發(fā),其他的所有請求都在本地處理。
ProxyPass "/images" "http://www.example.com/"
ProxyPa***everse "/images" "http://www.example.com/"
假如本地服務(wù)器地址為http://www1.example.com,當(dāng)請求http://www1.example.com/images/a.gif時,將代理為http://www.example.com/a.gif。
在沒有重定向的情況下,ProxyPa***everse 是可以省略的,否則一般情況下應(yīng)該將其設(shè)置為和 ProxyPass 相同。ProxyPa***everse 提供的是一種功能,它并不依賴于 ProxyPass(但一般都同時存在)。它的作用是防止重定向時客戶端無法正確訪問。例如,http://www.example.com/images/a.gif被代理為http://192.168.100.17/a.gif,如果此時 a.gif 被重定向到 b.gif,那么代理服務(wù)器返回給客戶端的將是http://192.168.100.17/b.gif。但客戶端是無法訪問后端內(nèi)網(wǎng)主機(jī) 192.168.100.17 的,于是出現(xiàn) file not found 錯誤。如果此時使用 ProxyPa***everse,那么代理服務(wù)器響應(yīng)給客戶端的請求會被調(diào)整為http://www.example.com/images/b.gif,這樣的請求再發(fā)給代理服務(wù)器,就能正確訪問。
2.2 負(fù)載均衡:后端成員
上面的配置中沒有添加后端服務(wù)器節(jié)點,無法享受反向代理的優(yōu)點。因此,有必要添加后端節(jié)點。添加的方法是使用 <proxy> 容器將后端節(jié)點定義成一個負(fù)載均衡組,各節(jié)點是該組中成員,然后代理目標(biāo)指向組名即可。
例如:
<Proxy balancer://myset>
BalancerMember http://www2.example.com:8080
BalancerMember http://www3.example.com:8080
ProxySet lbmethod=bytraffic
</Proxy>
ProxyPass "/images/" "balancer://myset/"
ProxyPa***everse "/images/" "balancer://myset/"
balancer://myset 告訴 httpd,它創(chuàng)建了一個負(fù)載均衡節(jié)點集合,名稱為 myset,此集合中有兩個后端成員。在上面的配置中,任意 / images 的請求都會代理至 2 個成員中的一個。ProxySet 指令指定 myset 均衡組使用的均衡算法為 bytraffic,即基于 I/O 流量字節(jié)數(shù)權(quán)重的算法。ProxySet 指令設(shè)置的是 Proxy 容器的公共屬性。
httpd 有 3 種負(fù)載均衡算法:
byrequests:默認(rèn)。基于請求數(shù)量計算權(quán)重。
bytraffic:基于 I/O 流量大小計算權(quán)重。
bybusyness:基于掛起的請求 (排隊暫未處理) 數(shù)量計算權(quán)重。
對于上面的示例,還可以稍加修改,使其支持更多功能。例如添加權(quán)重比例,使得某后端節(jié)點被轉(zhuǎn)發(fā)到的權(quán)重是另一節(jié)點的 3 倍,等待后端節(jié)點返回數(shù)據(jù)的超時時間為 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/"
ProxyPa***everse "/images" "balancer://myset/"
2.3 故障轉(zhuǎn)移
還可以再次調(diào)整實現(xiàn)故障轉(zhuǎn)移,例如當(dāng)所有負(fù)載節(jié)點都失敗時,指定一個備份節(jié)點 (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/"
ProxyPa***everse "/images/" "balancer://myset/"
其中成員 1、2、4、5 是負(fù)載節(jié)點,成員 3 是備份節(jié)點。當(dāng)所有負(fù)載節(jié)點都不健康時,將轉(zhuǎn)發(fā)請求給備份節(jié)點,并由備份節(jié)點處理請求,httpd 設(shè)置備份節(jié)點的方式很簡單,只需將狀態(tài)設(shè)置為 "H",表示 hot-standby。還需注意的是負(fù)載節(jié)點 4、5,它們額外的參數(shù)為 lbset=1,不寫時默認(rèn)為 0,這是負(fù)載均衡時的優(yōu)先級設(shè)置,負(fù)載均衡時總是先轉(zhuǎn)發(fā)給低數(shù)值的節(jié)點,也就是說數(shù)值越小,優(yōu)先級越高。所以上面的配置中,當(dāng)節(jié)點 1、2 正常工作時,只在它們之間進(jìn)行負(fù)載,此時節(jié)點 4、5 處于閑置狀態(tài)。只有當(dāng)節(jié)點 1、2 都失敗時,才會在節(jié)點 4、5 之間進(jìn)行負(fù)載。
2.4 提供負(fù)載狀態(tài)顯示頁面
<Location "/bm">
SetHandler balancer-manager
Require host localhost
Require ip 192.168.100
</Location>
然后在瀏覽器中輸入 http://server/bm 即可,返回結(jié)果如圖。
2.5 proxy 相關(guān)指令
2.5.1 ProxyPass 指令
該指令將遠(yuǎn)程服務(wù)器映射到本地主機(jī)上,但本地主機(jī)不是真實的服務(wù)器,而是遠(yuǎn)程主機(jī)的一個鏡像。這個鏡像通常稱為反向代理服務(wù)器或網(wǎng)關(guān)。該指令不能用于 <Directory>、< Files > 容器中,且使用該指令時通常會關(guān)閉正向代理,即ProxyRequests=off。
語法:
ProxyPass [path] !|url [key=value [key=value ...]]
path 參數(shù)為本地主機(jī)的 URL 路徑,url 參數(shù)為遠(yuǎn)程服務(wù)器的 url 一部分,不能包含查詢參數(shù)。如果第一個參數(shù) path 尾隨了斜線,則 url 部分也必須尾隨斜線,反之亦然。如果該指令封裝在 <Location> 容器中,則第一個參數(shù) path 可以省略,因為 Location 中已經(jīng)指定了 URL 路徑。如果第二個參數(shù)為 "!",則表示此 path 不使用反向代理功能。
例如:
<Location "/mirror/foo/">
ProxyPass "http://backend.example.com/foo/"
</Location>
當(dāng)訪問 http://server/mirror/foo/bar 時,將轉(zhuǎn)發(fā)到 http://backend.example.com 主機(jī)上,并請求該主機(jī)的 / foo/bar 文件。下面的配置指令與此等價。
ProxyPass "/mirror/foo/" "http://backend.example.com/foo/"
如果想讓某個子目錄不進(jìn)行反向代理,而是在本地處理。可以設(shè)置第二個參數(shù)為 "!"。例如,下面的配置中,/mirror/foo 會被代理,但 / mirror/foo/i 則不會被代理。
ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"
再需要說明的是連接池,httpd 會為后端節(jié)點創(chuàng)建連接池,httpd 會連接連接池中的各個節(jié)點。后端節(jié)點屬性相同的共享一個連接池。后端節(jié)點的屬性由 key=value 參數(shù)指定。以下是常見的一些屬性設(shè)置,完整的屬性見官方手冊。
keepalive=Off|On:默認(rèn)為 Off。設(shè)置 httpd 和后端節(jié)點之間是否開啟長連接,注意,這和 web 服務(wù)的長連接不一樣,此處設(shè)置的是反向代理服務(wù)器和后端節(jié)點兩者連接,當(dāng) httpd 將請求轉(zhuǎn)發(fā)給連接池中的一個節(jié)點,并等待返回數(shù)據(jù),當(dāng)數(shù)據(jù)返回完成后,連接立即關(guān)閉,如果開啟了長連接,連接暫時不關(guān)閉,只有等待均衡算法下次輪到該節(jié)點時才會再使用該連接。通常只有在 httpd 和后端節(jié)點間使用了防火墻時才設(shè)置為 On。
lbset=N:默認(rèn)為 0。設(shè)置后端節(jié)點的優(yōu)先級。數(shù)值 N 越低的,優(yōu)先級越高。httpd 總是會先嘗試優(yōu)先級高的,只有優(yōu)先級高的節(jié)點不可用時,才一會嘗試優(yōu)先級低的。
ping=N:默認(rèn)為 0。設(shè)置和 ajp13 協(xié)議 (不支持 http 協(xié)議) 通信時健康狀況檢查時間間隔。該 ping 只能檢查是否能 ping 通對方,也就是檢測是否能與對方通信。單位為秒,可以帶上后綴 "ms" 表示毫秒。更多的健康狀況檢查應(yīng)該使用 mod_proxy_hcheck 模塊。
retry=N:默認(rèn)為 60 秒。當(dāng)檢測到后端某節(jié)點錯誤狀態(tài) (error status) 時,將在每 N 秒后才轉(zhuǎn)發(fā)一次請求給該節(jié)點。設(shè)置為 0 表示正常轉(zhuǎn)發(fā)請求,不用任何等待時間。該屬性通常設(shè)置用來維護(hù)服務(wù)器下線然后再上線的情況。
status=VALUE:將節(jié)點手動置為何種狀態(tài)。包括以下幾種狀態(tài),各狀態(tài)可使用 "+"(默認(rèn)) 來賦予屬性,使用 "-" 來取消屬性。例如 "+H","S-E"。
D: 該節(jié)點被禁用,不再接受任何請求。
S: 該節(jié)點處于管理維護(hù)的目的被停止。
I: 將該節(jié)點設(shè)置為無視錯誤 (ignore-errors) 模式,此模式下 httpd 將認(rèn)為該節(jié)點可用,總會轉(zhuǎn)發(fā)請求給該節(jié)點。
H: 該節(jié)點處于 hot-standby 模式,該節(jié)點只有在其他所有后端節(jié)點都失效時才啟用。因此,該節(jié)點為備份節(jié)點。
E: 將該節(jié)點設(shè)置為錯誤狀態(tài) (error-state)。
N: 將該節(jié)點設(shè)置為 drain 模式,該模式只接受已預(yù)定粘滯會話的請求 sticky session,其他所有請求都會被忽略。
timeout=ProxyTimeout:設(shè)置 httpd 等待后端節(jié)點返回數(shù)據(jù)的超時時間。
如果使用了 "balancer://",例如前面的 balancer://myset,將創(chuàng)建一個虛擬的連接池。虛擬連接池中的各節(jié)點可共享部分屬性,也可以為每個節(jié)點設(shè)置上面所說的屬性。共享屬性使用 ProxySet 指令設(shè)置,常見的包括下面幾種:
lbmethod=METHOD:設(shè)置負(fù)載均衡算法。有三種:byrequests(默認(rèn)) 按照請求數(shù)量計算均衡節(jié)點;bytraffic 按照 io 流量計算均衡節(jié)點;bybusyness 按照繁忙程度計算計算均衡節(jié)點。
nofailover=On|Off:默認(rèn)為 off。session 不可用時是否轉(zhuǎn)移到其他具有相同 session 的節(jié)點上。如果后端節(jié)點不支持 session 復(fù)制,應(yīng)將此項設(shè)置為 on。
stickysession:設(shè)置 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/"
ProxyPa***everse "/images/" "balancer://myset/"
2.5.2 ProxyPassMatch 指令
正則匹配模式的 ProxyPass。例如:
ProxyPassMatch "^/(..gif)$" "http://backend.example.com/$1"
ProxyPassMatch "^/((?i)..php)$" "fcgi://127.0.0.1:9000/var/www/a.com/$1"
唯一需要注意的是,在正則匹配之前,遠(yuǎn)程 url 參數(shù)必須是能夠解析的 URL 地址。例如下面兩條指令,第一條指令將失敗,因為在正則解析前,url 參數(shù)無法解析為正確的 URL 地址,這是一個 bug,可以通過修改正則表達(dá)式的分組部分將 "/" 分離出去,正如下面的第二個指令。
ProxyPassMatch "^(/..gif)$" "http://backend.example.com:8000$1"
ProxyPassMatch "^/(..gif)$" "http://backend.example.com:8000/$1"
2.5.3 ProxySet 指令
設(shè)置 Proxy 后端節(jié)點的屬性。通常用來設(shè)置共享屬性,但也可以設(shè)置某一個節(jié)點的屬性。
例如:
<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
2.5.4 <Proxy> 容器
<Proxy> 容器用于封裝一組 proxy 相關(guān)指令,這些指令主要用于設(shè)置訪問權(quán)限、負(fù)載均衡成員組以及它們的屬性。
例如,下面的設(shè)置了只有 yournetwork.example.com 下的主機(jī)才能通過該 (正向或反向代理) 服務(wù)器訪問任意請求的內(nèi)容 (使用了 * 進(jìn)行通配)。
<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>
2.5.5 ProxyStatus 指令
ProxyStatus {on|off|full}決定是否開啟 server-status 中關(guān)于 proxy 的狀態(tài)信息,默認(rèn)為 off,full 是 on 的同義詞。
例如:
ProxyStatus on
<Location "/server-status">
SetHandler server-status
Require all granted
</Location>
以下是關(guān)于 proxy 相關(guān)的狀態(tài)示例:
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 0SSes 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
2.5.6 ProxyVia 指令
是否在響應(yīng)首部中添加 "Via:" 字段。可以設(shè)置為 On/Off 等。例如如設(shè)置為 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
2.6 ProxyPass 指令的排序和共享問題
ProxyPass 指令有個需要注意的問題,在匹配生效時,最先被匹配到的指令立即生效,后面的都將失效。但如果 ProxyPass 指令放在 <Location> 容器中時,由于容器中只能放置一個 ProxyPass 指令 (因為 path 參數(shù)一樣),此時匹配越精確的越優(yōu)先。
例如下面的指令,如果將兩個 ProxyPass 指令位置調(diào)換,則 / mirror/foo/i 也仍會被代理。
ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"
可以將它們分別定義到 <Location> 容器中,這樣就無需考慮位置順序,而是考慮匹配的精確程度,因為 Location 容器自身有加載順序優(yōu)先級。例如,下面的配置是可行的。
<Location "/mirror/foo/">
ProxyPass "http://backend.example.com/"
</Location>
<Location "/mirror/foo/i">
ProxyPass "!"
</Location>
還需考慮一個共享的問題。下面兩個指令中的 url 參數(shù)各有長短,且第一個 url 是第二個 url 的子串。這時第二個 ProxyPass 的屬性部分總是會使用第一個指令的屬性。因此 / examples/bar 的請求被轉(zhuǎn)發(fā)到 backend.example.com/examples/bar 時,它的屬性 timeout=60 而非 10。這樣的屬性共享可以減少創(chuàng)建連接池,相對來說更有效一些。
ProxyPass "/apps" "http://backend.example.com/" timeout=60
ProxyPass "/examples" "http://backend.example.com/examples" timeout=10
ProxyPass 指令自帶了 ping 屬性,可用于簡單判斷后端節(jié)點是否健康,只要 Ping 能通信就認(rèn)為是健康的。但顯然,對于 Http 服務(wù)來說,健康的指標(biāo)并不能簡單地通過它來判斷。例如,檢測某個頁面是否正常、是否允許某方法等。因此,httpd 提供了一個專門的健康狀況檢查模塊 mod_proxy_hcheck 用于個性化訂制檢查指標(biāo)。
檢查指標(biāo)也即檢查方法有以下幾種,由 hcmethod 指定:
TCP:檢查是否能與后端節(jié)點建立 TCP 套接字,這就是問對方 "你還活著嗎"。
OPTIONS:發(fā)送一個 HTTP OPTIONS 請求給后端節(jié)點。
HEAD:發(fā)送一個 HTTP HEAD 請求給后端節(jié)點。
GET:發(fā)送一個 HTTP GET 請求給后端節(jié)點。
該健康狀況檢查模塊認(rèn)為,只要 HTTP 方法的檢查指標(biāo)返回 2xx 或 3xx 狀態(tài)碼都認(rèn)為是健康的。
指定了檢查方法后,還需訂制檢查的細(xì)節(jié),例如檢查的時間間隔。包括以下幾項:
hcinterval:默認(rèn)為 30 秒。發(fā)送檢查的時間間隔,單位為秒。
hcuri:健康檢查時,追加在 URL 后的 URI。通常用于 GET 檢查方法。
hcpasses:默認(rèn)為 1。表示只有檢查了 N 次后都是通過的,才認(rèn)為該節(jié)點是健康的可再次啟用。
hcfails:默認(rèn)為 1。表示只有檢查了 N 次后都是失敗的,才認(rèn)為該節(jié)點已經(jīng)不健康,于是禁止使用該節(jié)點。
例如,以下是幾個健康檢查的配置示例:
<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"
ProxyPa***everse "/" "balancer://foo"
轉(zhuǎn)載請注明出處:https://www.cnblogs.com/f-ck-need-u/p/7651234.html
作者:駿馬金龍
出處:http://www.cnblogs.com/f-ck-need-u/
Linux&shell 系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html
網(wǎng)站架構(gòu)系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html
數(shù)據(jù)庫系列文章:http://www.cnblogs.com/f-ck-need-u/p/7586194.html
轉(zhuǎn)載于:https://blog.51cto.com/4507878/2116072
總結(jié)
以上是生活随笔為你收集整理的详细分析 apache httpd 反向代理的用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python学习笔记__4章 函数式编程
- 下一篇: 程序员永远不要再犯的5个编程错误