HAProxy健康检查失败而curl正常,主因是协议/路径不一致:HTTP/1.0无Host头被后端拒收、HTTPS后端误用HTTP检查、重定向未被处理、或源IP被ACL拦截,需针对性配置httpchk、ssl-hello-chk、状态码容错及网络策略。

HAProxy 后端健康检查失败,但用 curl 直连服务却完全正常——这是很典型的“协议/路径不一致”导致的误判,不是服务真挂了,而是 HAProxy 的健康检查请求没被后端正确识别或响应。
HTTP 健康检查默认发的是 HTTP/1.0,且 Host 头可能为空
HAProxy 默认的 option httpchk 会发送一个简化的 HTTP/1.0 请求(无 Host 头、无 User-Agent),例如:
GET /health HTTP/1.0\r\n\r\n
而很多现代 Web 服务(如 Nginx、Spring Boot、某些 API 网关)在收到无 Host 头或 HTTP/1.0 请求时,会直接返回 400、421 或直接关闭连接,导致 HAProxy 判定为失败。
解决方法:
- 显式指定 HTTP/1.1 + Host 头:
option httpchk GET /health HTTP/1.1\r\nHost: example.com - 在 backend 中配置:
http-check send hdr Host example.comhttp-check expect status 200
后端要求 TLS,但 health check 走的是明文 HTTP
如果后端只监听 HTTPS(如 443 端口),而 HAProxy 的 health check 配置仍用 httpchk 发送 HTTP 请求到 443,TCP 层能通,但 TLS 握手前就发了 HTTP 请求,服务端通常直接 reset 连接,HAProxy 收不到任何 HTTP 响应,判定为 down。
解决方法:
- 改用
option ssl-hello-chk(仅检测 TLS 握手是否成功,不校验内容) - 或启用 HTTPS 健康检查(需 HAProxy ≥ 2.2):
option httpchk GET /health
http-check send hdr Host example.com
http-check expect status 200
http-check expect ! rstring ^HTTP/1.[01] [45]
并确保 backend 使用ssl关键字和对应证书验证配置
健康检查路径返回 301/302 重定向,但 HAProxy 不跟随
比如后端把 /health 重定向到 /api/v1/health,而 HAProxy 默认不处理重定向(http-check 只看第一个响应的状态码),收到 301 就判定失败。
解决方法:
- 避免在健康检查路径上做重定向,直接返回 200
- 或显式允许特定跳转码:
http-check expect status 200 301 302
后端服务监听 localhost 或特定 IP,但 health check 源地址被防火墙/ACL 拦截
HAProxy 发起 health check 时使用的是本机任意可用源 IP(非 127.0.0.1),若后端有 iptables、cloud security group 或应用层白名单(如 Spring Security 的 allowed-origins),可能拒绝非预期来源的请求,而 curl localhost 因走 loopback 成功,造成错觉。
解决方法:
- 检查后端访问日志,确认 health check 请求是否到达;对比源 IP
- 临时放宽 ACL 或将 HAProxy 所在主机 IP 加入白名单
- 用
tcpdump抓包验证:在后端机器上执行tcpdump -i any port,再观察 HAProxy 日志触发 check 时是否有 SYN 包进来










