Haproxy 重定向跳轉設定 - 運維小結

散盡浮華發表於2018-12-26

 

前面已經詳細介紹了Haproxy基礎知識 , 今天這裡再贅述下Haproxy的重定向跳轉的設定.  haproxy利用acl來實現haproxy動靜分離,然而在許多運維應用環境中,可能需要將訪問的站點請求跳轉到指定的站點上,比如客戶單端訪問kevin.a.com需要將請求轉發到bobo.b.com或將http請求重定向到https請求,再比如當客戶端訪問出錯時,需要將錯誤code程式碼提示請求到指定的錯誤頁面,諸如此類需求實現,這種情況下就需要利用haproxy的重定向功能來達到此目的。

Haproxy是一款提供高可用性、負載均衡以及基於TCP(第四層)和HTTP(第七層)應用的代理軟體,支援虛擬主機,它是免費、快速並且可靠的一種解決方案。 Haproxy特別適用於那些負載特大的web站點,這些站點通常又需要會話保持或七層處理。Haproxy執行在時下的硬體上,完全可以支援數以萬計的 併發連線。並且它的執行模式使得它可以很簡單安全的整合進您當前的架構中, 同時可以保護你的web伺服器不被暴露到網路上。

Haproxy實現了一種事件驅動、單一程式模型,此模型支援非常大的併發連線數。多程式或多執行緒模型受記憶體限制 、系統排程器限制以及無處不在的鎖限制,很少能處理數千併發連線。事件驅動模型因為在有更好的資源和時間管理的使用者端(User-Space) 實現所有這些任務,所以沒有這些問題。此模型的弊端是,在多核系統上,這些程式通常擴充套件性較差。這就是為什麼他們必須進行優化以 使每個CPU時間片(Cycle)做更多的工作。

Haproxy支援連線拒絕 : 因為維護一個連線的開啟的開銷是很低的,有時我們很需要限制攻擊蠕蟲(attack bots),也就是說限制它們的連線開啟從而限制它們的危害。 這個已經為一個陷於小型DDoS攻擊的網站開發了而且已經拯救了很多站點,這個優點也是其它負載均衡器沒有的。

一. Haproxy實現request請求重定向
關於Hproxy 請求重定向主要會用到: redirect   redir 這兩類重定向配置語法。

1) redirect重定向用法: (redirect通常配置在haproxy acl部分)
redirect一般有兩個指令來執行HTTP重定向:
http-requets redirect       #此種方式支援日誌變數格式
redirect                           #此種方式只依賴於靜態字串

這兩個指令的語法是相同的,即redirect現在被認為是傳統和配置應該移動到http-request redirect形式。
還有一個主要區別是:http-request redirect使用日誌可變格式, 而redirect語句只依賴於靜態字串。

2) redirect三種重定向方式
a) 位置重定向
使用語法如下:
redirect location <loc> [code <code>] <option> [{if | unless} <condition>]

使用位置重定向,例如下面所示指令可以將使用者重定向到所提供的精確位置, 該位置可以是第三方URL連結,也可以是本地web服務的另一個訪問路徑.
1. http-request redirect location <loc> [code <code>] [<option>] [<condition>]
2. redirect location <loc> [code <code>] [<option>] [<condition>]

相關指令引數如下:
* <loc> :一個日誌格式變數 (或簡單的字串redirect語句)描述了新位置;
* code <code>(可選):HTTP重定向的狀態程式碼來執行。 此選項下的允許的狀態碼如下所示:

* <option>(可選):  可以是以下任何或組合的宣告:
1. set-cookie NAME[=value] :一個Set-Cookie頭部被新增到重定向。該cookie被命名為名稱,可以有一個可選的值值。
2. clear-cookie NAME[=]一個特殊的Set-Cookie頭被新增到重定向。該Cookie名為名稱和最大年齡的cookie引數設定為0,目的是為了指示瀏覽器刪除cookie。 

注意:  在於瀏覽器中,這是兩個不同的Cookie:NAME和NAME = 以上根據您的流量模式,必須將兩個語句適應。

* if | unless :  用於條件判斷
*<condition> (可選):用於匹配acl,一般為acl的名稱

b) 字首重定向
使用語法如下:
redirect prefix <loc> [code <code>] <option> [{if | unless} <condition>]

使用字首重定向,將使用者重定向到由concateneting建立了一個網址<pfx>和完整的原始URI路徑:
1. http-request redirect prefix <pfx> [code <code>] [<option>] [<condition>]
2. redirect prefix <pfx> [code <code>] [<option>] [<condition>]

相關指令引數如下:
* <pfx>: 一個日誌格式變數 (或簡單的字串redirect語句)描述了新的位置字首。
* code <code>(可選):HTTP重定向的狀態程式碼來執行。 此選項下的允許的狀態碼如下所示:

* <option>(可選): 可以是以下任何或組合的宣告:
drop-query :在執行串聯時從原來的URL刪除查詢字串
append-slash :配合使用drop-query ,在該URL的末尾新增一個“/”字元
set-cookie NAME[=value] :一個Set-Cookie頭部被新增到重定向。該cookie被命名為名稱,可以有一個可選的值值。
clear-cookie NAME[=] :一個特殊的Set-Cookie頭被新增到重定向。該Cookie名為名稱和最大年齡的cookie引數設定為0,目的是為了指示瀏覽器刪除cookie。

* if | unless :用於條件判斷
* <condition> (可選):用於匹配acl,一般為acl的名稱 

c) 協議(計劃)重定向(比如將http重定向到https)
使用語法如下:
redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]

使用位置重定向,例如下面所示指令可以將使用者重定向到所提供的新的http協議url連結, 一般用於非安全連結跳轉到安全連結,比如http跳轉到https上
1. http-request redirect scheme <schloc> [code <code>] [<option>] [<condition>]
2. redirect scheme <sch> [code <code>] [<option>] [<condition>]

相關指令引數如下:
* <loc> :一個日誌格式變數 (或簡單的字串redirect語句)描述了新位置;
* code <code>(可選):HTTP重定向的狀態程式碼來執行。 此選項下的允許的狀態碼如下所示:

* <option>(可選): 可以是以下任何或組合的宣告:
1. set-cookie NAME[=value] :一個Set-Cookie頭部被新增到重定向。該cookie被命名為名稱,可以有一個可選的值值。
2. clear-cookie NAME[=]一個特殊的Set-Cookie頭被新增到重定向。該Cookie名為名稱和最大年齡的cookie引數設定為0,目的是為了指示瀏覽器刪除cookie。

注意: 在於瀏覽器中,這是兩個不同的Cookie:NAME和NAME = 以上根據你的流量模式,必須將兩個語句適應。

* if | unless :用於條件判斷
* <condition> (可選):用於匹配acl,一般為acl的名稱

一個簡單的例項:

acl http      ssl_fc,not
http-request redirect scheme https if http

下面是redirect 綜合應用的一個小示例:

acl clear      dst_port  80
acl secure     dst_port  8080
acl login_page url_beg   /login
acl logout     url_beg   /logout
acl uid_given  url_reg   /login?userid=[^&]+
acl cookie_set hdr_sub(cookie) SEEN=1 

redirect prefix   https://kevin.com set-cookie SEEN=1 if !cookie_set
redirect prefix   https://kevin.com           if login_page !secure
redirect prefix   http://kevin.com drop-query if login_page !uid_given
redirect location http://kevin.com/           if !login_page secure
redirect location / clear-cookie USERID=      if logout

總結: redirect三種重定向可以混合使用,比較常用的有redirect prefix redirect location這兩種方式,從某種理解上可以交差使用;

3) redir重定向用法:(redir通常配置在haproxy backend部分)
使用redir 會將發往backend的站點服務請求均以302狀態響應發給需要重定向的server服務或站點,此時haproxy不需要向後端web server提交請求;需要注意的是,在prefix後面不能使用/,且不能使用相對地址,以避免造成迴圈,例如:

frontend  main *:80
    default_backend app
backend app
    balance roundrobin
    server node1 127.0.0.1:81 check weight 3 redir http://www.kevin.com

上面配置含義:所有發往localhost:81的請求做重定向,重定向到www.kevin.com因此可以實現單臺伺服器的重定向

又例如,如果我們要講訪問的站點重定向到grace.com

frontend  main *:80
    default_backend  app
backend app
    balance roundrobin
    server node1 127.0.0.1:81 check weight 3 redir http://www.grace.com

注意:redir只做跳轉,如客戶端輸入:http://ip ,將會跳轉到指定的頁面上,此時客戶端的頁面的頁面也會跳轉到指定的頁面上,之後所有的請求都會遞交到該站點(前提該站點可以與客戶端通訊),而不再發往haproxy代理站點,haproxy也不需要往後端web server提交客戶端發過來的請求。

二. haproxy實現error重定向
格式為: errorfile 錯誤程式碼code 錯誤程式碼響應提示頁路徑
* errorfile 即根據客戶端頁面錯誤code狀態將指定的錯誤狀態頁面提示給客戶端,比如友情提示頁面,一般如下:

errorfile 403 /etc/haproxy/errorfiles/403.http
errorfile 500 /etc/haproxy/errorfiles/500.http
errorfile 502 /etc/haproxy/errorfiles/502.http
errorfile 503 /etc/haproxy/errorfiles/503.http
errorfile 504 /etc/haproxy/errorfiles/504.http

例如:如果想訪問403頁面重定向到其他頁面的話 (errorloc),則參考以下配置:

frontend web_server
    bind *:80
    default_backend webserver
    acl badguy src 172.16.50.10
    block if badguy
    errorloc 403 http://grace.com/         #定義錯誤頁面重定向

errorfile  表示在使用者請求不存在的頁面時,返回一個頁面給客戶端而非有haproxy生成的錯誤程式碼,可用於所有段中;
格式: errorfile <code> <file>

errorloc  表示請求錯誤時,返回一個HTTP重定向至某URL的資訊,可以用於所有端中;
格式: errorloc <code> <url>

總結: 錯誤重定向可以更加友好地提示客戶端錯誤狀態,比如做定製頁面化跳轉,以及網站維護升級等等,當出現錯誤時,可以及時跳轉到預定好錯誤提示頁面上。 

三. haproxy定義規則
1) haproxy常用的acl匹配條件

-i:不區分<value>中模式字元的大小寫;
 -f:從指定的檔案中載入模式;    

path_beg:用於測試請求的URL是否以<string>指定的模式開頭
    例:匹配url以/static、/images、/javascript /stylesheets開頭
    acl url_static  path_beg  -i  /static /images /javascript /stylesheets

path_end:用於測試請求的URL是否以<string>指定的模式結尾
    例:匹配url以jpg、gif、png、css、js結尾
    acl url_static  path_end -i .jpg .gif .png .css .js

hdr_beg:用於測試請求報文的指定首部的開頭部分是否符合<string>指定的模式
    例:匹配請求的主機以img、video、download或ftp開頭
    acl host_static hdr_beg(host) -i img. video. download. ftp.
    即匹配訪問的域名是img.bobo.com,video.bobo.com,download.bobo.com,ftp.bobo.com

url_beg:匹配的是整個url
    例:匹配url為http://www.bobo.com.com
    acl is_bobo.com url_beg http://www.bobo.com.com
    use_backend bobo.com if is_bobo.com

dst_port:判斷請求的埠

hdr_sub:判斷客戶的user-agent
    例:判斷客戶端的user-agent是否為手機
    acl shouji hdr_sub(user-agent) -i android iphone

2) haproxy定義分發規則

根據請求的主機頭,實現不同專案的請求,分發到不同的backend

hdr_beg(host):判斷主機頭

例如:
acl is_www hdr_beg(host) -i www.bobo.com.com
acl is_wap hdr_beg(host) -i wap.bobo.com.com
acl is_erp hdr_beg(host) -i erp.bobo.com.com
acl is_interface hdr_beg(host) -i interface.bobo.com.com
use_backend tomcat_erp_v2 if is_erp
use_backend tomcat_interface_v2 if is_interface
use_backend tomcat_web_v2 if is_www
use_backend tomcat_mobile_v2 if is_wap

通過定義以上規則即可實現訪問不同的域名分發到不同的backend

3) haproxy定義重定向規則

prefix:表示重定向url
location:表示重定向訪問路徑,即url不變,url後邊跟的路徑發生改變

例如:
redirect prefix http://weihu.bobo.com.com/PC if is_www
redirect prefix http://weihu.bobo.com.com/H5 if is_wap

說明:
當訪問is_www時,重定向到weihu.bobo.com.com/PC
當訪問is_wap時,重定向到weihu.bobo.com.com/H5

4) haproxy定義放行規則

僅放行通過驗證的IP地址或者IP範圍段;

例如:
如果訪問的是is_www,但來源IP不是指定的IP時,用http-request deny進行拒絕;

acl is_www hdr_beg(host) -i www.bobo.com.com
acl is_dns src 172.16.60.0/24 218.65.212.0/24
http-request deny if is_www  !is_dns(滿足條件的直接進行拒絕)   

也可以寫為:
acl is_www hdr_beg(host) -i www.bobo.com.com
acl is_dns src 172.16.60.0/24 218.65.212.0/24
user_backend www if is_www  is_dns(兩個條件同時滿足才使用後端的www)

說明:
源地址有多個時,用空格進行隔開

5) haproxy定義手機只能訪問手機端,電腦端只能訪問電腦端規則

例如:
當手機訪問www.bobo.com時轉發到wap.bobo.com
當電腦訪問wap.bobo.com時轉發到www.bobo.com

配置如下:
acl is_shouji hdr_sub(user-agent) -i android iphone
acl is_diannao hdr_beg(host) www
redirect prefix http://wap.bobo.com if shouji 
redirect prefix http://www.bobo.com if is_diannao !is_shouji

Haproxy 重定向跳轉 - 示例 1

1) 首先每個域名解析到自己的ip
www.kevin.com   172.16.51.100
www.grace.com   172.16.51.200
www.bobo.com    172.16.51.210

2) 域名重定向
acl name_redirectA hdr_beg(host) -i www.kevin.com
redirect prefix http://www.bobo.com/A if name_redirectA

acl name_redirectB hdr_beg(host) -i  www.grace.com
redirect prefix http://www.bobo.com/B if name_redirectB

3) 跳轉規則
acl name_A hdr_beg(host) -i www.kevin.com
acl name_B hdr_beg(host) -i www.grace.com
acl name_C hdr_beg(host) -i www.bobo.com
acl api_reqA path_beg -i /A/api
acl api_reqB path_beg -i /B/api
use_backend appserver_8081 if name_A or name_B      #匹配"或"的規則
use_backend appserver_8082_A if name_C api_reqA     #匹配"和"的規則
use_backend appserver_8082_B if name_C api_reqB       

backend appserver_8081
   balance source
   server web1 172.16.51.171:8081 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
   server web2 172.16.51.174:8081 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

backend appserver_8082_A
   server web1 172.16.51.180:80 weight 3 check inter 2000 rise 2 fall 3
 
backend appserver_8082_B
   server web1 172.16.51.180:80 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

Haproxy 重定向跳轉 - 示例 2

redirect location <to> [code <code>] <option> [{if | unless} <condition>]
redirect prefix <to> [code <code>] <option> [{if | unless} <condition>] 重定向,相當於rewrite
 
示例配置如下:
acl shibo hdr_reg(host) -i ^(shibo.kevin.com|forum.kevin.com)       #使用正則匹配 
acl shibo_path path_beg -i /shibo                #url 目錄 
acl youxi path_beg -i /youxi               
acl static path_end -i .html .css .js      #url 結尾檔案 
acl php path_end -i .php  
acl jsp path_end -i .jsp .do  
 
use_backend shibo_pool if shibo or shibo_path       #注意"或"的匹配用"or"
use_backend youxi_pool if youxi 
use_backend static_pool if static  
use_backend php_pool if php 
use_backend jsp_pool if jsp 
default_backend www.kevin.com                 

#當滿足host_bb.cn的策略,跳轉(重定向)到http://www.bb.cn
acl host_bb.cn hdr_beg(host) -i (bb.cn|beijing.com)
redirect prefix http://www.bb.cn if host_bb.cn
 
#有個問題: haproxy能否在接到一個請求時選擇一個後端伺服器,然後301重定向url 。
#主要原因是他有5個1G的出口,這樣就能充分利用其頻寬。
#測試了一下是可以的
frontend free
   bind *:80
   default_backend lvs2
backend lvs2
   mode http
   option forwardfor header ORIG_CLIENT_IP
   server free174 172.16.51.16:8081 redir http://free71-174-grace.com:8081 weight 10 rise 3 fall 5 check inter 2000 
   server free173 172.16.51.15:8081 redir http://free71-173-grace.com:8081 weight 10 rise 3 fall 5 check inter 2000
      
#當輸入負載均衡機器的域名後,url會直接變成http://free71-17(3|4)-grace.com:8081.
 
acl monitor hdr_beg(host) -i monitor.kevin.com        #定義ACL名稱(monitor),對應的請求的主機頭是monitor.kevin.com  
acl shibo hdr_reg(host) -i ^(shibo.kevin.com|forum.kevin.com)  #使用正則匹配 
acl host_bb.cn hdr_beg(host) -i bb.cn
acl host_hui.cn hdr_beg(host) -i beijing.com
redirect prefix http://www.bb.cn if host_bb.cn
redirect prefix http://www.bb.cn if host_hui.cn
 
frontend localhost
    bind *:80
    bind *:443 ssl crt /etc/ssl/bb.web/bb.web.pem
    redirect scheme https if !{ ssl_fc }
    mode http
    default_backend nodes

# 上面配置中, 新增了redirect導向,如果連線不是通過SSL連線的,它將http重定向到https
 
acl host_bb.cn hdr_beg(host) -i bb.cn
acl host_jiu.cn hdr_beg(host) -i beijing.com
acl www_jiu.cn hdr_beg(host) -i www.beijing.com
acl host_hui.cn hdr_beg(host) -i pp.com
acl www_hui.cn hdr_beg(host) -i www.pp.com
redirect prefix http://www.bb.cn if host_bb.cn
redirect prefix http://www.bb.cn if host_jiu.cn
redirect prefix http://www.bb.cn if www_jiu.cn
redirect prefix http://www.bb.cn if host_hui.cn
redirect prefix http://www.bb.cn if www_hui.cn
 
訪問bb.cn,beijing.com,www.beijing.com,pp.com,www.pp.cpm 都跳轉到http://www.bb.cn

Haproxy 重定向跳轉 - 示例 3 (手機規則匹配)

一.  線上業務的實際需求
現在根據業務的實際需要,有以下幾種不同的需求。如下:

a) 轉發所有手機請求
所有通過手機端訪問http.shibo.com域名的話,全部轉發到http://www.shibo.com這個地址,而PC端不受此限制。

b) 根據url進行轉發
如果手機端請求http.shibo.com這個域名的url中,以docs或者manager這兩個關鍵詞開頭的話,把該請求轉發到後端的伺服器,而PC端不受此限制。

也就是說手機端訪問具體的url地址的話,可以正常訪問。如果是直接訪問http.shibo.com域名的話,直接把該請求轉發到http://www.shibo.com這個地址。

============================================================
二.  haproxy配置
下面根據不同的業務需求進行配置haproxy,如下。
a) 轉發所有手機請求配置
要把所有的手機端請求轉到www.shibo.com這個地址,需要我們首先把訪問的終端匹配出來,haproxy可以通過hdr_sub(user-agent)這個引數把手機端匹配出來。

手機端匹配出來後,我們就可以定義相應的規則,把手機端的請求轉發到www.shibo.com這個地址了。haproxy.cf配置檔案如下:
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
global
   log 127.0.0.1 local0
   log 127.0.0.1 local1 notice
   maxconn 4096
   uid 188
   gid 188
   daemon
   tune.ssl.default-dh-param 2048

defaults
   log global
   mode http
   option httplog
   option dontlognull
   option http-server-close
   option forwardfor except 127.0.0.1
   option redispatch
   retries 3
   option redispatch
   maxconn 2000
   timeout http-request 10s
   timeout queue 1m
   timeout connect 10s
   timeout client 1m
   timeout server 1m
   timeout http-keep-alive 10s
   timeout check 10s
   maxconn 3000

listen admin_stats
   bind 0.0.0.0:1080
   mode http
   option httplog
   maxconn 10
   stats refresh 30s
   stats uri /stats
   stats auth admin:admin
   stats hide-version

frontend weblb
   bind *:80
   acl is_http hdr_beg(host) http.shibo.com
   acl ua hdr_sub(user-agent) -i android iphone
   redirect prefix http://www.shibo.com if ua
   use_backend httpserver if is_http

backend httpserver
    balance source
    server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3


溫馨提示: 
在以上配置檔案中,有以下兩行需要注意:
acl ua hdr_sub(user-agent) -i android iphone
redirect prefix http://www.shibo.com if ua

這兩行:
第一行是第一個ua規則,該規則是判斷是否是手機端。
注意:在此手機端,我們只匹配了安卓手機和iphone。
第二行是跳轉規則,如果匹配是手機端的話,那麼直接跳轉到http://www.shibo.com這個地址。


如果是PC端的話,預設跳轉到httpserver這個後端伺服器組。
以上配置是一臺伺服器對外只提供一個域名訪問的請求,如果有兩個域名的話,就要進行如下配置:
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
global
   log 127.0.0.1 local0
   log 127.0.0.1 local1 notice
   maxconn 4096
   uid 188
   gid 188
   daemon
   tune.ssl.default-dh-param 2048

defaults
   log global
   mode http
   option httplog
   option dontlognull
   option http-server-close
   option forwardfor except 127.0.0.1
   option redispatch
   retries 3
   option redispatch
   maxconn 2000
   timeout http-request 10s
   timeout queue 1m
   timeout connect 10s
   timeout client 1m
   timeout server 1m
   timeout http-keep-alive 10s
   timeout check 10s
   maxconn 3000

listen admin_stats
   bind 0.0.0.0:1080
   mode http
   option httplog
   maxconn 10
   stats refresh 30s
   stats uri /stats
   stats auth admin:admin
   stats hide-version

frontend weblb
   bind *:80
   acl is_http hdr_beg(host) http.shibo.com
   acl is_haproxy hdr_beg(host) haproxy.shibo.com
   acl ua hdr_sub(user-agent) -i android iphone
   redirect prefix http://www.shibo.com if ua !is_haproxy
   use_backend haproxyserver if ua is_haproxy
   use_backend haproxyserver if is_haproxy
   use_backend httpserver if is_http

backend httpserver
   balance source
   server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

backend haproxyserver
   balance source
   server web1 127.0.0.1:7070 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3


b) 測試轉發所有手機請求
在手機瀏覽器中輸入http.shibo.com會自動跳轉到http://www.shibo.com這個地址。

c) 根據url進行轉發配置
根據手機端請求的url進行轉發的話,首先也是需要匹配出手機端,然後定義url路徑規則。最後結合手機端和url路徑規則,進行跳轉。
haproxy具體配置檔案,如下:
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
global
   log 127.0.0.1 local0
   log 127.0.0.1 local1 notice
   maxconn 4096
   uid 188
   gid 188
   daemon
   tune.ssl.default-dh-param 2048

defaults
   log global
   mode http
   option httplog
   option dontlognull
   option http-server-close
   option forwardfor except 127.0.0.1
   option redispatch
   retries 3
   option redispatch
   maxconn 2000
   timeout http-request 10s
   timeout queue 1m
   timeout connect 10s
   timeout client 1m
   timeout server 1m
   timeout http-keep-alive 10s
   timeout check 10s
   maxconn 3000

listen admin_stats
   bind 0.0.0.0:1080
   mode http
   option httplog
   maxconn 10
   stats refresh 30s
   stats uri /stats
   stats auth admin:admin
   stats hide-version

frontend weblb
   bind *:80
   acl is_http hdr_beg(host) http.shibo.com
   acl is_docs url_beg /docs /manager
   acl ua hdr_sub(user-agent) -i android iphone
   redirect prefix http://www.shibo.com if ua !is_docs
   use_backend httpserver if ua is_docs
   use_backend httpserver if is_http

backend httpserver
   balance source
   server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

溫馨提示:
在上述配置檔案中,需要以下幾行解釋下:

acl is_docs url_beg /docs /manager
定義一個is_docs規則。如果url以/docs或者/manager開頭的,則全部屬於該規則。

acl ua hdr_sub(user-agent) -i android iphone
redirect prefix http://www.shibo.com if ua !is_docs
這兩行首先是匹配出手機端,然後如果是手機端訪問,並且訪問的不是is_docs規則的話,則直接跳轉到http://www.shibo.com這個地址。

use_backend httpserver if ua is_docs
這條命令是,如果是手機端訪問,並且訪問的是is_docs規則的話,則直接跳轉到httpserver這個後端伺服器組。

如果是PC端的話,預設跳轉到httpserver這個後端伺服器組。

d) 測試根據url進行轉發
手機端訪問http://http.shibo.com/docs/這個連線的話,是可以直接訪問的。


============================================================
三.  其他haproxy相關配置
上面說明了有關手機的相關配置,在實際的生產環境中,有時候還會碰到一些奇奇怪怪的要求。
比如要求所有手機端訪問的http.shibo.com,轉到指定的頁面。haproxy主要配置檔案如下:
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............

frontend weblb
   bind *:80
   acl is_http hdr_beg(host) http.shibo.com
   acl ua hdr_sub(user-agent) -i android iphone
   redirect prefix http://www.shibo.com/?p=10624 if ua
   use_backend httpserver if is_http

backend httpserver
   balance source
   server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

以上配置是所有手機端訪問的,都跳轉到http://www.shibo.com/?p=10624這個頁面。

haproxy重定向跳轉 - 示例4 (修改路徑, 即重寫URL)

1) 訪問https://www.shibo.com/guo-hui 重定向跳轉到 https://www.xiaobo.com/an-hui
frontend https
    option http-server-close
    reqadd X-Forwarded-Proto:\ https

    acl shi_bo hdr(host) -i www.shibo.com
    acl guo_hui path_beg /guo-hui
    acl an_hui path_beg /an-hui

    reqirep ^([^\ ]*\ /)guo-hui(.*) \1an-hui\2 if shi_bo guo_hui              #注意中間的空格, 以及\1 和 \2; 
    redirect prefix https://www.xiaobo.com code 301 if shi_bo an_hui

2) 訪問http://front-end/app-2/do-that 重定向跳轉到 http://back-end/app-2-another-path/do-that
frontend http   
   acl do-that path_end -i /app-2/do-that
   use_backend server1 if do-that

backend server1
   reqirep ^([^\ :]*)\ /app-2/(.*)  \1\ /app-2-another-path/\2
   server server 172.16.60.51

3) 訪問原請求為 http://www.kevin.com/OLD/ab... 
    重定向到 http://www.kevin.com/NEW/ab...

在nginx裡可以通過rewrite來實現跳轉配置, 配置內容如下:
server {
    listen 80;
    server_name www.kevin.com;
    location / {
        rewrite ^/OLD(.*) /NEW$1 permanent;
        proxy_pass http://backend_www_kevin_com;
    }
}

在haproxy裡重定向跳轉的配置如下:
frontend web80
    bind *:80
    
    acl domain_www_kevin_com hdr_beg(host) -i www.kevin.com kevin.com
    acl url_old  url_beg   -i /old

    reqirep ^([^\ ]*)\ /old(.*) \1\ /new\2  if domain_www_kevin_com url_old
    use_backend kevin_com   if domain_www_kevin_com

最後總結:
通過以上haproxy和nginx的重寫配置, 可以看出二者配置的不同在於:
-  http://www.kevin.com/old,後端真實伺服器收到的請求被重寫為 /new/ ,並且瀏覽器收到 HTTP/1.1 302 Location: /new/ , 
   位址列改為 http://www.kevin.com/new/
-  http://www.kevin.com/old/,或者 http://www.kevin.com/old/ab... 後端真實伺服器收到的請求被重寫為 /new/ ,
   瀏覽器並沒有收到 302 , 位址列依舊為 http://www.kevin.com/old/

4) haproxy URL 重新 , 如下兩個規範配置
reqirep ^([^\ ]*)\ /books/(.*) \1\ /books.php?title=\2
reqirep ^([^\ ]*)\ /(.*)  \1\ /wdn/\2

# 注意中間的空格, 以及\1 和 \2

5) reqirep可以修改http的頭; 如果haproxy 配置裡要替換主機頭, 則:
   在backend 選項下面加入:
   reqirep ^Host:\ (.*) Host:\ 標識

haproxy重定向跳轉 - 示例5 (錯誤/黑白名單/動靜分離/讀寫(上傳和下載)分離的重定向 )

1) haproxy 錯誤重定向(403), 即黑名單設定
   
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
  
acl blacklist src 172.16.51.250
http-request deny if blacklist
  
如上配置後, 當來源ip是172.16.51.250時, 就直接返回一個403錯誤頁面!!
  
=============================================================
當haproxy配置裡限制一個來源ip訪問時, 直接給使用者返回403錯誤頁面, 會顯得不太友好, 所以haproxy重定向應運而生.
如下配置, 當來源ip是172.16.51.250時, 直接重定向跳轉到172.16.51.10的8000埠的錯誤頁面
   
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
   
acl badhost src 172.16.51.250
block if badhost
errorloc 403 http://172.16.51.10:8000
   
在172.16.51.10機器上部署nginx, 埠為8000, 然後在nginx根目錄的index.html裡設定錯誤頁面資訊,
錯誤頁面資訊可以自己隨便定義, 比如"抱歉, 頁面臨時出錯, 運維工程師正在搶修中, 請耐心等待~"
   
2) haproxy 黑名單重定向
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
   
acl  badhost src 172.16.51.250
redirect location http://172.16.51.10:8000 if  badhost
   
在172.16.51.10機器上部署nginx, 埠為8000, 然後在nginx根目錄的index.html裡設定錯誤頁面資訊,
錯誤頁面資訊可以自己隨便定義, 比如"抱歉, 這是一個禁止訪問的來源ip地址!請嘗試從其他機器訪問."
   
3) haproxy 網頁重定向
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
   
acl shibo.com hdr_beg(host) -i shibo.com
redirect code 301 location http://www.shibo.com if shibo.com
   
溫馨提示:
如果不寫301,只寫code預設是302,臨時重定向 (不推薦), 加上301則表示永久重定向
   
4) haproxy 訪問IP自動跳轉到域名
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
   
acl 172.16.51.10 hdr(host) -i 172.16.51.10
redirect code 301 location http://www.shibo.com if 172.16.51.10
   
5) haproxy 讀寫分離 配置 (即上傳和下載分離)
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
   
acl read method GET
acl read method HEAD
acl write method PUT
acl write method POST
use_backend dynamic if write
default_backend static
   
backend static                               #"上傳"讀取操作的負載代理.
    balance   roundrobin
    server    web1 172.16.51.30:80 check           
   
backend  dynamic                         #"下載"寫入操作的負載代理
    balance   roundrobin
    server    web2 172.16.51.40:80 check           
  
6) haproxy 動靜分離 配置
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
  
frontend public
      bind            *:80 name clear
      #bind         172.16.51.10:443 ssl crt /etc/haproxy/haproxy.pem
      #use_backend    static if { hdr_beg(host) -i img }
      #use_backend    static if { path_beg /img /css   }
      use_backend    static2 if { path_end -i .php   }
      default_backend static1
  
# The static backend backend for 'Host: img', /img and /css.
backend static1
      balance     roundrobin
      server        statsrv1 172.16.51.20:80 check inter 1000
  
backend static2
      balance     roundrobin
      server       statsrv2 172.16.51.30:80 check inter 1000

7) haproxy的白名單設定
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
frontend tcp-8080-front
     bind *:8080
     mode tcp
     default_backend     tcp-8080-back
 
tcp-8080-back
     mode tcp
     balance leastconn
     tcp-request content accept if { src -f /usr/local/haproxy/white_ip_list }
     tcp-request content reject
     server tcp-8080 10.1.27.20:8080

配置中/usr/local/haproxy/white_ip_list檔案即為白名單檔案, 在檔案裡配置允許的白名單地址: 一行一個IP或者IP段。

haproxy 重定向跳轉 - 示例6

[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
acl  admin_req  path_beg  -i  /admin
use_backend  admin_80  if  admin_req

backend admin_80
      mode   http
      balance   roundrobin
      server   apphost01_8083  172.16.50.133:80  check inter 2000 fall 3


接著去172.16.50.133伺服器上看下tomcat配置
[root@tomcat-133 ~]# vim /usr/local/tomcat/conf/server.xml
.............
     <Context docBase="/data02/kevin-web" path="/" reloadable="false"/>

[root@tomcat-133 ~]# cd /data02/kevin-web
[root@tomcat-133 kevin-web]# ls
admin  adminwechat  index.html  jquery.2.1.4.min.js  META-INF  WEB-INF  kevin-web-0.0.1-SNAPSHOT.war
[root@tomcat-133 kevin-web]# ls 
bobo.html

最後, 可驗證:
訪問http://www.kevin.com/admin/bobo.html  實際上返回的是172.16.50.133伺服器的/data02/kevin-web/admin/bobo.html頁面內容

haproxy 重定向跳轉 - 示例7 (haproxy 代理 https)

haproxy代理https有兩種方式:
1)haproxy伺服器本身提供ssl證照,後面的web伺服器走正常的http
2)haproxy伺服器本身只提供代理,後面的web伺服器走https(配置ssl證照)
 
=====================================================
第一種方式:haproxy伺服器本身提供ssl證照
 
注意: 需要編譯haproxy的時候支援ssl
編譯引數:
[root@localhost ~]# make TARGET=linux26 USE_OPENSSL=1 ADDLIB=-lz
[root@localhost ~]# ldd haproxy | grep ssl
libssl.so.10 => /usr/lib64/libssl.so.10 (0x00007fb0485e5000)
 
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
frontend https_frontend
    bind *:443 ssl crt /etc/ssl/certs/servername.pem
    mode http
    option httpclose
    option forwardfor
    reqadd X-Forwarded-Proto:\ https
    default_backend web_server
 
backend web_server
    mode http
    balance roundrobin
    cookie SERVERID insert indirect nocache
    server s1 172.16.50.150:80 check cookie s1
    server s2 172.16.50.151:80 check cookie s2
 
 
溫馨提示:  這裡的pem 檔案是下面兩個檔案合併而成
[root@localhost ~]# cat servername.crt servername.key |tee servername.pem
 
 
=====================================================
第二種方式:haproxy伺服器本身只提供代理,沒有ssl證照 (一般我們常用的就是這種方式)
 
這種方式,haproxy不需要重新編譯支援ssl,簡單方便,只需要後面的web伺服器配置好ssl即可。
 
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
.............
.............
frontend https_frontend
    bind *:443
    mode tcp
    default_backend web_server
 
backend web_server
    mode tcp
    balance roundrobin
    stick-table type ip size 200k expire 30m
    stick on src
    server s1 172.16.50.150:443
    server s2 172.16.50.151:443
 
溫馨提示:  這種模式下mode 必須是tcp模式!!!!!!!!

haproxy重定向跳轉 - 示例8 (http, https的有關重定向, 案例分析)

需要提前說明下:
下面配置操作全部是在haproxy1.5.4版本下進行配置和通過測試的!
haproxy1.3版本以下haproxy配置引數可能不能使用,所以需要注意haproxy的版本號
以下的haproxy配置可以線上上生產環境直接使用的!

一、業務要求
根據系統業務的實際需要,有以下幾種不同的需求:

1.1) http跳轉https
把所有請求http://http.kevin.com的地址全部跳轉為https://http.kevin.com這個地址。

1.2) http與https並存
伺服器同時開放http://http.kevin.com和https://http.kevin.com的訪問形式。

1.3) 同臺伺服器不同域名之間的https與http
同一臺伺服器對http.kevin.com域名訪問的全部跳轉為https://http.kevin.com,而對haproxy.kevin.com訪問走http協議,
也就是跳轉到http://haproxy.kevin.com這個地址。

1.4) 同臺伺服器多域名均使用https
同一臺伺服器對http.kevin.com和haproxy.kevin.com訪問走http是協議。


二、配置haproxy, 實現以上業務需求

2.1) http跳轉https的haproxy配置檔案內容
說實話haproxy的https配置要比nginx配置簡單的多了,只需要加入幾行程式碼即可實現https的功能。
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
global
   log 127.0.0.1 local0
   log 127.0.0.1 local1 notice
   maxconn 4096
   uid 188
   gid 188
   daemon
   tune.ssl.default-dh-param 2048

defaults
   log global
   mode http
   option httplog
   option dontlognull
   option http-server-close
   option forwardfor except 127.0.0.1
   option redispatch
   retries 3
   option redispatch
   maxconn 2000
   timeout http-request 10s
   timeout queue 1m
   timeout connect 10s
   timeout client 1m
   timeout server 1m
   timeout http-keep-alive 10s
   timeout check 10s
   maxconn 3000

listen admin_stats
   bind 0.0.0.0:1080
   mode http
   option httplog
   maxconn 10
   stats refresh 30s
   stats uri /stats
   stats auth admin:admin
   stats hide-version

frontend weblb
   bind *:80
   acl is_http hdr_beg(host) http.kevin.com
   redirect scheme https if !{ ssl_fc }
   bind *:443 ssl crt /etc/haproxy/kevin.com.pem
   use_backend httpserver if is_http

backend httpserver
   balance source
   server web1 127.0.0.1:7070 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3


溫馨提示:
在以上配置檔案中,只要需要注意下面四個選項的配置:
tune.ssl.default-dh-param 2048                #因為我們的SSL金鑰使用的是2048bit加密,所以在此進行宣告。

acl is_http hdr_beg(host) http.kevin.com
redirect scheme https if !{ ssl_fc }
bind *:443 ssl crt /etc/haproxy/kevin.com.pem
# 這三行表示把所有訪問http.kevin.com這個域名的請求,全部轉發到https://http.kevin.com這個連線。

測試:
發現在瀏覽器中,無論輸入的是http.kevin.com, 還是http://http.kevin.com, 亦或是https://http.kevin.com,都會自動跳轉到https://http.kevin.com。
這樣就達到了,把所有的http請求跳轉到https的目的。


2.2) http與https並存配置
haproxy要實現http和https並存的話,配置也很簡單,只需要把haproxy分別監控不同的埠就行,配置檔案如下:
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
global
   log 127.0.0.1 local0
   log 127.0.0.1 local1 notice
   maxconn 4096
   user haproxy
   group haproxy
   daemon
   tune.ssl.default-dh-param 2048

defaults
   log global
   mode http
   option httplog
   option dontlognull
   retries 3
   option redispatch
   maxconn 2000
   timeout connect 5000ms
   timeout client 50000ms
   timeout server 50000ms

listen admin_stats
   bind 0.0.0.0:1080
   mode http
   option httplog
   maxconn 10
   stats refresh 30s
   stats uri /stats
   stats auth admin:admin
   stats hide-version

frontend weblb
   bind *:80
   acl is_http hdr_beg(host) http.kevin.com
   use_backend httpserver if is_http

backend httpserver
   balance source
   server web1 127.0.0.1:7070 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

frontend weblb443
   bind *:443 ssl crt /etc/haproxy/kevin.com.pem
   acl is_443 hdr_beg(host) http.kevin.com
   use_backend httpserver443 if is_443

backend httpserver443
   balance source
   server web1 127.0.0.1:7070 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3


溫馨提示:
在以上配置檔案中,定義了兩個前端,一個前端用於監聽80埠,也就是http協議。另外一個前端監聽443埠,也就是https協議。
此時haproxy會根據客戶端請求的協議進行分發,如果發現客戶端請求的是http協議,則把該請求分發到監聽80埠的前端。
如果發現客戶端請求的是https協議,則把該請求分發到監聽443埠的前端。如此就達到了haproxy讓http和https並存的要求。

測試:
通過測試會發現,在瀏覽器中如果輸入的是http://http.kevin.com或者是http.kevin.com都會直接跳轉到http://http.kevin.com,
而輸入的是https://http.kevin.com,則只會跳轉到https://http.kevin.com。
如此就到達了,我們業務的要求實現http和https並存。


2.3) 同臺伺服器不同域名之間的https與http配置
同臺伺服器不同域名之間的http和https配置比較複雜,第一需要監聽兩個埠,第二還要根據不同的域名進行分發。
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
global
   log 127.0.0.1 local0
   log 127.0.0.1 local1 notice
   maxconn 4096
   uid 188
   gid 188
   daemon
   tune.ssl.default-dh-param 2048

defaults
   log global
   mode http
   option httplog
   option dontlognull
   option http-server-close
   option forwardfor except 127.0.0.1
   option redispatch
   retries 3
   option redispatch
   maxconn 2000
   timeout http-request 10s
   timeout queue 1m
   timeout connect 10s
   timeout client 1m
   timeout server 1m
   timeout http-keep-alive 10s
   timeout check 10s
   maxconn 3000

listen admin_stats
   bind 0.0.0.0:1080
   mode http
   option httplog
   maxconn 10
   stats refresh 30s
   stats uri /stats
   stats auth admin:admin
   stats hide-version

frontend weblb
   bind *:80
   acl is_haproxy hdr_beg(host) haproxy.kevin.com
   acl is_http hdr_beg(host) http.kevin.com
   redirect prefix https://http.kevin.com if is_http
   use_backend haproxyserver if is_haproxy

backend haproxyserver
   balance source
   server web1 127.0.0.1:9090 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

frontend weblb443
   bind *:443 ssl crt /etc/haproxy/kevin.com.pem
   acl is_443 hdr_beg(host) http.kevin.com
   use_backend httpserver443 if is_443

backend httpserver443
   balance source
   server web1 127.0.0.1:7070 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3


溫馨提示:
同臺伺服器不同域名之間的https與http配置,上面配置了兩個前端一個用於監聽80埠,並且根據不同的域名進行跳轉。
在80埠的規則中,如果客戶端請求的是http.kevin.com,這個域名的話,則haproxy會把該請求直接跳轉到https://http.kevin.com。
如果是haproxy.kevin.com,這個域名的話,則分發到後端的伺服器。
另外一個前端用於監聽443埠,用於分發客戶端https://http.kevin.com的請求。

測試: 
可以發現在瀏覽器中輸入haproxy.kevin.com會跳轉到http://haproxy.kevin.com這個地址,
而如果輸入的是http.kevin.com或者是http://http.kevin.com,亦或是https://http.kevin.com的話,都會跳轉到https://http.kevin.com。
如此就達到了上面的業務要求,同臺伺服器上訪問haproxy.kevin.com直接跳轉到80埠,如果訪問的是http.kevin.com域名的話則跳轉
到https://http.kevin.com這個地址。


2.4) 同臺伺服器多域名均使用https配置
要使同臺伺服器的兩個設定多個域名都使用https協議的話,配置很簡單。只需要在haproxy中啟用各自的https配置即可。
[root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
global
   log 127.0.0.1 local0
   log 127.0.0.1 local1 notice
   maxconn 4096
   uid 108
   gid 116
   daemon
   tune.ssl.default-dh-param 2048

defaults
   log global
   mode http
   option httplog
   option dontlognull
   option http-server-close
   option forwardfor except 127.0.0.1
   option redispatch
   retries 3
   option redispatch
   timeout http-request 10s
   timeout queue 1m
   timeout connect 10s
   timeout client 1m
   timeout server 1m
   timeout http-keep-alive 10s
   timeout check 10s
   maxconn 3000

listen admin_stats
   bind 0.0.0.0:1080
   mode http
   option httplog
   maxconn 10
   stats refresh 30s
   stats uri /stats
   stats auth admin:admin
   stats hide-version

frontend web80
   bind *:80
   acl is_http hdr_beg(host) http.kevin.com
   redirect scheme https if !{ ssl_fc }

   bind *:443 ssl crt /etc/haproxy/kevin.com.pem
   acl is_haproxy hdr_beg(host) haproxy.kevin.com
   redirect scheme https if !{ ssl_fc }

   bind *:443 ssl crt /etc/haproxy/kevin.com.pem
   use_backend httpserver if is_http
   use_backend haproxyserver if is_haproxy

backend httpserver
   balance source
   server web1 127.0.0.1:6060 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

backend haproxyserver
   balance source
   server web1 127.0.0.1:9090 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3

測試:
在瀏覽中無論是輸入http.kevin.com、http://http.kevin.com,還是haproxy.kevin.com、http://haproxy.kevin.com,都會跳轉到相應的https地址。
這也達到了業務的要求

相關文章