如何配置HAProxy粘性会话忽略客户端IP(适配WAF场景)
嘿,我来帮你一步步解决这个会话持久化的问题~ 核心原因是你的WAF用了多个随机出口IP,HAProxy原来靠stick on src(也就是WAF的IP)绑定会话,一旦WAF换IP,会话就跳去别的服务器了。下面我给你详细拆解WAF厂商提的两个方案,结合你现有的配置给出具体修改方法:
方案1:用X-Real-IP生成会话Cookie(保留IP关联的粘性)
这个方案的思路是让HAProxy认真实客户端IP(WAF会通过X-Real-IP请求头把这个IP传给你),而不是WAF的出口IP,这样不管WAF换多少个IP,只要客户端IP不变,会话就不会跳。分HTTP和HTTPS场景处理:
针对HTTP前端&后端(http_frontend + bk_http)
你的bk_http已经是mode http,能直接读取HTTP头,改起来很简单:
backend bk_http mode http balance roundrobin # 把原来的stick on src换成WAF传的真实客户端IP stick on req.hdr(X-Real-IP) cookie SRVNAME insert server web1 ip1:80 check cookie SA check server web2 ip2:80 check cookie SB check
敲黑板:先确认你的WAF确实在转发请求时加了
X-Real-IP头,别白忙活~
针对HTTPS前端&后端(https_frontend + bk_https)
现在你的https_frontend是纯TCP转发(mode tcp),这种模式下HAProxy看不到HTTP头(包括X-Real-IP),得先让HAProxy解密HTTPS流量才能读取这个头:
- 先改
https_frontend为HTTP模式,配置好你的SSL证书:
frontend https_frontend bind *:443 ssl crt /path/to/your/ssl-cert.pem # 替换成你实际的证书路径 mode http default_backend bk_https
- 再改
bk_https后端,用真实IP绑定会话:
backend bk_https mode http balance leastconn stick-table type ip size 2000k expire 30m stick on req.hdr(X-Real-IP) # 用真实客户端IP绑定会话 cookie SRVNAME insert server web1 ip1:443 check cookie web1 server web2 ip2:443 check cookie web2
要是你的WAF已经帮你解密了HTTPS(转发给HAProxy的是HTTP流量),那只需要把
https_frontend的mode tcp改成mode http就行,不用配SSL证书~
方案2:移除会话Cookie的IP关联(只靠Cookie维持粘性)
这个方案更简单:彻底放弃IP绑定,全靠HAProxy插入的SRVNAME Cookie来认会话。只要客户端带着这个Cookie,HAProxy就会把请求发到对应的服务器,完全不受WAF IP变化的影响。
修改HTTP后端(bk_http)
把原来的stick on src删掉,保留Cookie配置就行:
backend bk_http mode http balance roundrobin cookie SRVNAME insert # 只靠Cookie维持会话 server web1 ip1:80 check cookie SA check server web2 ip2:80 check cookie SB check
修改HTTPS后端(bk_https)
同样删掉stick on src和对应的stick-table,保留Cookie配置:
backend bk_https mode tcp balance leastconn # 删掉stick-table和stick on src这两行 default-server inter 1s cookie SRVNAME insert server web1 ip1:443 check cookie web1 server web2 ip2:443 check cookie web2
小提示:如果可以的话,建议把HTTPS后端改成
mode http(让HAProxy终止SSL),这样Cookie的处理会更稳定可靠~
最后给你几个测试建议
- 改配置前先备份原文件,别手滑搞崩了;
- 用
curl -v测试:发一次请求,看响应头里有没有Set-Cookie: SRVNAME=xxx,然后带着这个Cookie再发请求,检查是不是路由到同一台服务器; - 选方案1的话,记得在HAProxy日志里加
%[req.hdr(X-Real-IP)]字段,验证真实客户端IP有没有被正确传递。
内容的提问来源于stack exchange,提问作者webserver

