HAProxy 怎么设置 HTTP 请求头 X-Forwarded-For 传递真实 IP

文章导读
在 HAProxy 中传递客户端真实 IP,核心是在配置文件中启用 option forwardfor 参数,并确保后端 Web 服务器(如 Nginx 或 Apache)配置为信任并解析该头部,否则后端只能看到负载均衡器的 IP。
📋 目录
  1. A 完整配置示例
  2. B 后端服务器配置
  3. C curl 验证测试
  4. D 后端应用代码获取示例
  5. E 常见坑与风险
A A

在 HAProxy 中传递客户端真实 IP,核心是在配置文件中启用 option forwardfor 参数,并确保后端 Web 服务器(如 Nginx 或 Apache)配置为信任并解析该头部,否则后端只能看到负载均衡器的 IP。

先说结论:HAProxy 需开启 option forwardfor,后端需配置信任该头部来源,且不可无条件信任 X-Forwarded-For 以防伪造。

  • 适合:HAProxy 作为七层负载均衡反向代理的场景
  • 先准备:确认 HAProxy 配置权限及后端 Web 服务器类型(Nginx/Apache)
  • 验收:通过后端日志或应用代码获取到的 IP 是否为客户端公网 IP

完整配置示例

在 HAProxy 配置的 listen 或 backend 模块下,添加以下参数即可开启透传。以下是完整的 backend 配置块示例,可直接复用:

backend web_servers
    balance roundrobin
    option forwardfor
    option http-server-close
    http-request set-header X-Real-IP %[src]
    server web1 192.168.1.10:80 check
    server web2 192.168.1.11:80 check

若需自定义头部名称,可指定 header 参数:

option forwardfor header X-Real-IP

注意:建议配合 option http-server-close 使用以确保连接正确处理,option httpclose 在较新版本中已不推荐。

后端服务器配置

1. 配置后端 Nginx

在后端 Nginx 配置中,必须声明信任 HAProxy 的 IP 段,并指定解析头部:

HAProxy 怎么设置 HTTP 请求头 X-Forwarded-For 传递真实 IP
set_real_ip_from 192.168.1.0/24; # HAProxy 的 IP 段
real_ip_header X-Forwarded-For;
real_ip_recursive on;

2. 配置后端 Apache

仅修改日志格式无法让应用逻辑获取真实 IP,需安装并配置 mod_remoteip 模块以替换 REMOTE_ADDR:

# 启用模块(Debian/Ubuntu)
a2enmod remoteip

# 配置文件 httpd.conf 或 sites-available 配置
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 192.168.1.0/24
RemoteIPInternalProxy 10.0.0.0/8

配置完成后重启 Apache,应用层获取的 REMOTE_ADDR 即为真实客户端 IP。

curl 验证测试

使用 curl 命令发送请求并查看 verbose 输出,确认头部是否生成:

curl -v http://your-domain.com/

在后端服务器抓包或查看访问日志,确认 X-Forwarded-For 字段存在且包含客户端公网 IP。例如 Nginx 日志格式配置:

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
              '$status $body_bytes_sent "$http_referer" '
              '"$http_user_agent" "$http_x_forwarded_for"';

后端应用代码获取示例

配置完成后,不同语言获取真实 IP 的方式如下:

HAProxy 怎么设置 HTTP 请求头 X-Forwarded-For 传递真实 IP

PHP:

// 配置 mod_remoteip 后,直接使用
$ip = $_SERVER['REMOTE_ADDR'];
// 或未配置模块时手动获取
// $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];

Python (Flask):

from flask import request
# 需配置 ProxyFix 或信任代理
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1)
ip = request.remote_addr

Java (Spring):

String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    ip = request.getRemoteAddr();
}

常见坑与风险

1. 安全信任问题:X-Forwarded-For 可被客户端伪造,后端必须仅信任来自 HAProxy 等可控代理的请求,不可直接采信公网请求中的该头部。

2. 多级代理链:若中间还有其他代理,X-Forwarded-For 会是 IP 链(如 client, proxy1, proxy2),后端需配置 recursive 模式或取第一个 IP,注意 HAProxy 默认是追加而非覆盖。

3. 连接模式影响:HAProxy 工作在隧道模式时可能仅对连接的第一个请求附加头部,需确保配置了 option http-server-close 以保证每个请求都处理。