haproxy默认只读取/etc/haproxy/haproxy.cfg,需用systemctl reload而非restart重载配置;backend中避免使用localhost,应明确指定127.0.0.1或[::1];务必添加option forwardfor和x-forwarded-proto头;acl规则须按从具体到宽泛顺序书写。

HAProxy 配置文件写在哪、怎么加载
HAProxy 不读 /etc/haproxy/haproxy.cfg 以外的默认路径,哪怕你装的是源码版或容器版,启动时没指定 -f 就只认这个位置。改完配置不能靠重启服务“自动生效”,必须显式重载:用 sudo systemctl reload haproxy(不是 restart),否则新配置压根不进内存。
常见错误是改了 haproxy.cfg 却执行 systemctl restart haproxy,结果服务起不来——因为语法错或端口被占,但你以为只是“没生效”,其实是直接 crash 了。检查方法很简单:sudo haproxy -c -f /etc/haproxy/haproxy.cfg,返回 Configuration file is valid 才算过第一关。
backend 转发到本机服务时,localhost 和 127.0.0.1 行为不同
在 backend 块里写 server app1 localhost:8000 看似合理,但 HAProxy 默认用 IPv6 解析 localhost,而你的 Python/Node 服务可能只监听 IPv4 的 127.0.0.1,导致连接被拒绝,错误日志里出现 Connection refused 却查不到原因。
实操建议统一用明确地址:
- 本地服务固定用
127.0.0.1:8000(IPv4)或[::1]:8000(IPv6),别碰localhost - 如果后端是 Docker 容器,别写
localhost——宿主机的 localhost ≠ 容器网络里的 localhost,得用宿主机真实 IP 或 Docker 自定义网络的网关地址 - 加
check参数时,确保目标服务真在监听且能响应健康检查请求,否则 HAProxy 会把 server 标成DOWN
HTTP 重定向和 HTTPS 强制跳转容易漏掉 X-Forwarded-For
HAProxy 默认不转发原始客户端 IP,X-Forwarded-For 头要手动加。如果你在 frontend 里配了 redirect scheme https if !{ ssl_fc },但后端应用还拿 request.remote_addr 做限流或日志,就会发现所有请求都来自 HAProxy 本机 IP(比如 127.0.0.1)。
必须在 frontend 或 backend 中加两行:
option forwardfor
http-request set-header X-Forwarded-Proto https if { ssl_fc }
注意:如果前端还有 Nginx 或 CDN,X-Forwarded-For 可能已被污染,这时得配合 http-request set-header X-Real-IP %[hdr(X-Forwarded-For),first] 并信任上游代理 IP 段(用 http-request deny 拦非可信来源)。
ACL 规则顺序决定匹配结果,写反就全失效
HAProxy 的 use_backend 和 http-request redirect 都依赖 ACL,而 ACL 是从上到下逐条匹配,一旦命中就停止判断。比如你想把 /api/ 走 backend api,其余走 static,但把 path_beg / 的规则写在最前面,那所有请求都会进 static,/api/ 根本没机会匹配。
正确顺序原则:
- 更具体的路径放前面(
path_beg /api/v2/→path_beg /api/→path_beg /) - 带 host 条件的 ACL 要放在 path 类之前,避免 host 不匹配却因 path 先中而误判
- 用
sudo haproxy -d -f /etc/haproxy/haproxy.cfg启动调试模式,看日志里每条请求实际匹配了哪条 ACL
ACL 写错不会报错,只会静默走默认逻辑,这是最常被忽略的点——出问题时先看日志里 matched 关键字出现在哪一行。










