Haproxy ACL 访问控制

本文整理 Haproxy 常见的 ACL(访问控制列表)示例与测试步骤,包含按域名、Host 前缀、URL 路径、IP 黑/白名单等场景的配置与测试方法。
目录
- 简介
- 实验环境准备(hosts)
- 基础 HAProxy 配置
- ACL 示例
- 按域名后缀分流(.com)
- 按 Host 前缀分流(bbs.)
- 按路径分流(/lee)
- 按源 IP 黑名单(deny)
- 按源 IP 白名单(allow-only)
- 测试命令与预期输出
- 常见 ACL 表达式速查
- 注意事项
简介
ACL(Access Control List)是 HAProxy 中非常常用的功能,用于基于请求的不同特征(Host、Header、Path、Source IP 等)做分流、拒绝或其它条件判断。通过 acl 定义条件,通过 use_backend、http-request deny、http-request redirect 等指令执行动作。
实验环境准备(在浏览器或 curl 的主机上做本地域名解析)
- Windows:编辑
C:\Windows\System32\drivers\etc\hosts(文中有 gif 示例,示意本机做解析) - Linux:编辑
/etc/hosts
示例(Linux):
bash
# 在 /etc/hosts 中添加测试域名解析
172.25.254.100 www.timinglee.org bbs.timinglee.org news.timinglee.org login.timinglee.org www.lee.org www.lee.com
测试:
bash
ping bbs.timinglee.org

基础 HAProxy 配置
最小的前端 + 两个后端示例:
bash
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
# 默认将请求路由到 webserver-80-web1(下方会根据 ACL 修改)
use_backend webserver-80-web1
backend webserver-80-web1
server web1 192.168.0.10:80 check inter 3s fall 3 rise 5
backend webserver-80-web2
server web2 192.168.0.20:80 check inter 3s fall 3 rise 5
重载服务:
bash
systemctl restart haproxy.service
ACL 示例
下面的示例都在 frontend webcluster 中定义 acl,并根据条件 use_backend 或 http-request deny。
1) 按域名后缀分流(以 .com 结尾走 web1,其他走 web2)
解释:hdr_end(host) 检查 Host 头是否以指定字符串结尾(忽略端口号)。
haproxy
#在访问的网址中,所有以.com 结尾的访问10,其他访问20
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl test hdr_end(host) -i .com #acl列表
use_backend webserver-80-web1 if test #acl列表访问匹配
default_backend webserver-80-web2 #acl列表访问不匹配
backend webserver-80-web1
server web1 192.168.0.10:80 check inter 3s fall 3 rise 5
backend webserver-80-web2
server web2 192.168.0.20:80 check inter 3s fall 3 rise 5
测试(客户端):
bash
curl http://www.lee.com # 期望返回 webserver1 (192.168.0.10)
curl http://www.lee.org # 期望返回 webserver2 (192.168.0.20)
2) 按 Host 前缀分流(Host 以 bbs. 开头)
haproxy
acl head hdr_beg(host) -i bbs.
use_backend webserver-80-web1 if head
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl test hdr_end(host) -i .com #acl列表
acl head hdr_beg(host) -i bbs.
use_backend webserver-80-web1 if head
default_backend webserver-80-web2
backend webserver-80-web1
server web1 192.168.0.10:80 check inter 3s fall 3 rise 5
backend webserver-80-web2
server web2 192.168.0.20:80 check inter 3s fall 3 rise 5
说明:hdr_beg(host) 检查 Host 头是否以某字符串开头。
3) 按路径分流(URL 路径以 /lee 开头)
说明:常用表达式有 path_beg(路径以开头匹配)、path(完整路径匹配)、path_reg(正则匹配)。示例使用 path_beg。
haproxy
frontend webcluster
bind *:80
mode http
acl path_lee path_beg -i /lee
use_backend webserver-80-web1 if path_lee
default_backend webserver-80-web2
示例在后端 webserver 上准备页面:
bash
# 在 web1 和 web2 上创建内容以便区分
mkdir -p /var/www/html/lee/test/
echo "lee - 192.168.0.10" > /var/www/html/lee/index.html # web1
echo "lee/test - 192.168.0.10" > /var/www/html/lee/test/index.html
# web2 类似,内容写入 web2 的相应目录
测试:
bash
curl http://172.25.254.100/lee/ # 期望 webserver1 的内容
curl http://172.25.254.100/lee/test/ # 期望 webserver1 的内容
curl http://172.25.254.100/index.html # 期望 webserver2 的内容(没有 /lee 前缀)
4) 源 IP 黑名单(deny)
把特定源 IP 拒绝访问(返回 403):
haproxy
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl pathdir base_dir -i /lee
use_backend webserver-80-web1 if pathdir
default_backend webserver-80-web2 #acl列表访问不匹配
backend webserver-80-web1
server web1 192.168.0.10:80 check inter 3s fall 3 rise 5
backend webserver-80-web2
server web2 192.168.0.20:80 check inter 3s fall 3 rise 5
[root@webserver1+2 ~]# mkdir -p /var/www/html/lee/
[root@webserver1+2 ~]# mkdir -p /var/www/html/lee/test/
[root@webserver1 ~]# echo lee - 192.168.0.10 > /var/www/html/lee/index.html
[root@webserver1 ~]# echo lee/test - 192.168.0.10 > /var/www/html/lee/test/index.html
[root@webserver2 ~]# echo lee - 192.168.0.20 > /var/www/html/lee/index.html
[root@webserver2 ~]# echo lee/test - 192.168.0.10 > /var/www/html/lee/test/index.html
测试(来自被列入黑名单的主机):
bash
curl http://172.25.254.100
# 返回:
# <html><body><h1>403 Forbidden</h1>Request forbidden by administrative rules.</body></html>
5) 源 IP 白名单(只允许某些源,其他拒绝)
常见写法是"除非来自白名单,否则拒绝":
bash
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend webcluster
bind *:80
mode http
acl test hdr_end(host) -i .com #acl列表
use_backend webserver-80-web1 if test #acl列表访问匹配
default_backend webserver-80-web2 #acl列表访问不匹配
acl invalid_src src 172.25.254.1
http-request deny if ! invalid_src
backend webserver-80-web1
server web1 192.168.0.10:80 check inter 3s fall 3 rise 5
backend webserver-80-web2
server web2 192.168.0.20:80 check inter 3s fall 3 rise 5
说明:!allowed_src 表示不在白名单中的请求会被拒绝,白名单中的源可以继续访问。
测试命令与示例输出(摘录)
示例命令(在测试主机上):
bash
# 按域名测试
curl www.lee.com # 期望: webserver1 - 192.168.0.10
curl www.lee.org # 期望: webserver2 - 192.168.0.20
# 按路径测试
curl 172.25.254.100/lee/
curl 172.25.254.100/lee/test/
curl 172.25.254.100/index.html
# 源 IP 被拒绝的测试
curl 172.25.254.100 # 若客户端 IP 在黑名单 => 403 Forbidden
(你的原始示例中已有交互输出,已在上文保留预期说明。)
常见 ACL 表达式速查
- hdr(host) / hdr_end(host) / hdr_beg(host) / hdr_sub(host) : 匹配 Host 头或 Host 的某部分
- hdr() / hdr_end() / hdr_beg() : 匹配任意指定 Header 的值
- path_beg : URL path 以 prefix 开头
- path_end : URL path 以 suffix 结尾(视 HAProxy 版本)
- path_reg : 使用正则表达式匹配路径
- src <ip|network> : 请求源地址
- method : 请求方法(GET/POST 等)
ACL 名称可以任意起(如 host_dot_com、path_lee),后续通过 if <aclname> 或 unless <aclname> 使用。
注意事项与建议
- 编辑完
/etc/haproxy/haproxy.cfg后,重启或平滑重载 HAProxy:- systemctl restart haproxy.service
- 或者更安全的平滑重载:systemctl reload haproxy.service(视系统支持)
- ACL 的判断顺序会影响结果,复杂规则建议通过注释和有意义的 ACL 名称来管理。
- 使用
http-request deny会返回 403;如果想返回 404 或重定向,可使用http-request redirect或http-request deny deny_status 404(具体语法请参考你所用 HAProxy 版本文档)。 - 不同 HAProxy 版本对某些匹配关键字(例如
path_end、path_dir等)的支持可能不同,请以你当前安装的 HAProxy 版本文档为准。常用且兼容度高的写法:path_beg、path、hdr_*、src。 - 在生产环境请谨慎测试 ACL 规则,避免因规则错误导致不必要的访问中断。
参考
- 官方文档(根据所用版本参考对应章节:ACL & sample fetches)
equest deny deny_status 404`(具体语法请参考你所用 HAProxy 版本文档)。 - 不同 HAProxy 版本对某些匹配关键字(例如
path_end、path_dir等)的支持可能不同,请以你当前安装的 HAProxy 版本文档为准。常用且兼容度高的写法:path_beg、path、hdr_*、src。 - 在生产环境请谨慎测试 ACL 规则,避免因规则错误导致不必要的访问中断。
参考
- 官方文档(根据所用版本参考对应章节:ACL & sample fetches)
- 你的实验截图与命令输出(已整合到上文示例)