Appearance
ACL 与请求路由
ACL(Access Control List)是 HAProxy 最强大的功能之一,通过条件匹配实现精细的请求路由、访问控制、流量限制等。
ACL 基础语法
haproxy
acl <acl_name> <criterion> [flags] [operator] <value> [...]常用匹配条件(criterion)
| 条件 | 说明 | 示例 |
|---|---|---|
path | 请求路径(不含参数) | path /api |
path_beg | 路径前缀匹配 | path_beg /api |
path_end | 路径后缀匹配 | path_end .jpg |
path_reg | 路径正则匹配 | path_reg ^/user/\\d+$ |
url | 完整 URL | url \\.png$ |
url_param | URL 参数值 | url_param(session_id) |
hdr | HTTP Header | hdr(Host) example.com |
hdr_beg | Header 开头匹配 | hdr_beg(Host) api. |
hdr_reg | Header 正则 | hdr_reg(User-Agent) .*curl.* |
src | 客户端源 IP | src 192.168.1.0/24 |
src_port | 客户端源端口 | src_port 12345 |
dst | 目标 IP | dst 10.0.0.1 |
method | HTTP 方法 | method POST |
req.ver | HTTP 版本 | req.ver eq 1.1 |
beslie | 后端服务器名 | beslie web1 |
status | 响应状态码 | status 200 |
cook | Cookie 值 | cook(JSESSIONID) |
wait_for_end | 等待请求体完全接收 | - |
常用 ACL 示例
按路径前缀路由
haproxy
frontend http_front
bind *:80
# 定义 ACL
acl is_api path_beg /api
acl is_admin path_beg /admin
acl is_static path_beg /static /images /css /js
# 路由
use_backend api_backend if is_api
use_backend admin_backend if is_admin
use_backend static_backend if is_static
default_backend web_backend按域名路由(虚拟主机)
haproxy
frontend http_front
bind *:80
bind *:443 ssl crt /etc/ssl/certs/
acl is_api hdr_beg(Host) api.
acl is_cdn hdr_beg(Host) cdn.
acl is_main hdr(Host) example.com
use_backend api_backend if is_api
use_backend cdn_backend if is_cdn
use_backend web_backend if is_main按源 IP 访问控制
haproxy
frontend http_front
bind *:80
# 阻止特定 IP
acl blocked_ip src -f /etc/haproxy/blocked.lst
http-request deny if blocked_ip
# 只允许内网访问管理后台
acl is_internal src 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12
http-request deny if ! is_internal按 User-Agent 路由
haproxy
acl is_mobile hdr_reg(User-Agent) (iPhone|Android)
acl is_bot hdr(User-Agent) -i -f /etc/haproxy/bots.lst
acl is_wechat hdr(User-Agent) -i -m beg WeChat按请求方法限制
haproxy
acl is_delete method DELETE
acl is_upload method POST
http-request deny if is_delete
http-request deny if ! is_upload按 URL 参数
haproxy
# /products?id=123 形式
acl has_id url_param(id) -m found
acl valid_id url_param(id) -m int gt 0
http-request deny if !has_id or !valid_id条件组合
使用 and、or 以及 ! 取反:
haproxy
# 移动端 + API 路径
acl mobile_api path_beg /api and hdr_beg(Host) m.
use_backend api_mobile_backend if mobile_api
# API 路径 但不是 Webhook
acl is_api path_beg /api
acl is_webhook path_beg /api/webhook
use_backend api_backend if is_api and ! is_webhook
# IP 白名单 且 非管理员路径
acl whitelist src -f /etc/haproxy/whitelist.lst
acl admin_path path_beg /admin
http-request allow if whitelist
http-request deny if admin_pathhttp-request / http-response 指令
在请求或响应阶段执行动作:
haproxy
# 请求阶段
http-request allow # 允许
http-request deny [reason] [<status code>] # 拒绝
http-request redirect location <url> # 重定向
http-request set-header <name> <value> # 设置 Header
http-request del-header <name> # 删除 Header
http-request replace-header <name> <regex> <fmt> # 替换 Header
http-request set-cookie <name> <value> # 设置 Cookie
http-request add-header <name> <value> # 添加 Header
# 响应阶段
http-response allow
http-response deny
http-response set-header <name> <value>
http-response set-cookie <name> <value> [direct] [nocache]
http-response replace-value <name> <regex> <fmt>实用示例
强制 HTTPS 重定向:
haproxy
frontend http_front
bind *:80
http-request redirect scheme https if !{ ssl_fc }添加真实 IP 到 Header:
haproxy
frontend http_front
bind *:80
http-request set-header X-Real-IP %[src]
http-request set-header X-Forwarded-For %[src]
http-request set-header X-Forwarded-Proto https if { ssl_fc }限制单 IP 并发连接数:
haproxy
frontend http_front
bind *:80
stick-table type ip size 100k expire 30s store conn_rate(100s)
acl too_many_conns sc1_conn_rate gt 50
tcp-request connection reject if too_many_connsUser-Agent 黑名单:
haproxy
frontend http_front
acl bad_bot hdr(User-Agent) -i -m sub -f /etc/haproxy/bad-bots.lst
http-request deny if bad_botACL 调试
开启 ACL 日志以便调试:
haproxy
defaults
option httplog # 完整 HTTP 日志
option logasce # 客户端看到的是服务器时间
log stdout local0
frontend http_front
http-request log-format "ACL: is_api=%is_api src=%[src]"查看实时日志:
bash
tail -f /var/log/haproxy/haproxy.log | grep ACLACL 性能注意
- ACL 在内存中缓存结果,复杂正则 (
hdr_reg) 匹配开销较大 - 常用 ACL 放前面,减少匹配次数
- 频繁使用的 ACL 尽量用
path_beg而不是正则