如果 Nginx 前面部署了负载均衡器、CDN 或反向代理,默认日志和程序获取到的客户端 IP 会是代理服务器的 IP,需要在 Nginx 配置中启用 ngx_http_realip_module 模块,指定信任的代理网段并读取对应的 HTTP 头。
先说结论:必须启用 realip 模块且正确设置信任源,否则后端拿到的永远是代理 IP。
- 适合:Nginx 作为反向代理后端,或背后有 LB/CDN 的场景
- 先准备:确认上游代理传递的 Header 名称及代理服务器 IP 段
- 验收:后端程序获取的 IP 与客户端真实公网 IP 一致
命令速用版
以下是核心配置片段,建议放入 http 块中,根据实际代理 IP 修改 set_real_ip_from:
http {
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 192.168.1.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
server {
listen 80;
...
}
}
为什么会这样
当请求经过代理服务器时,TCP 连接的源地址变成了代理服务器的地址。Nginx 默认记录的是 TCP 连接源 IP。为了传递真实用户 IP,代理通常会在 HTTP 请求头中附加字段,如 X-Forwarded-For 或 X-Real-IP。Nginx 需要被明确告知信任哪些代理发来的请求,并读取哪个 header 字段来替换 remote_addr。
分步处理
- 确认模块支持:执行
nginx -V,检查输出中是否包含`--with-http`_realip_module。大多数主流发行版安装包默认包含,若没有需重新编译。 - 获取代理 IP 段:联系负载均衡管理员或查阅云厂商文档,获取 LB 或 CDN 的出口 IP 网段。不要随意信任任意 IP。
- 修改配置文件:在 nginx.conf 的 http 块或具体 server 块中添加配置。set_real_ip_from 指定信任的代理 IP,real_ip_header 指定存放真实 IP 的 header 名。
- 检查语法并重载:执行
nginx -t确认配置无误,然后执行nginx -s reload生效。
怎么验证是否生效
- 查看访问日志:检查 access.log 中的$remote_addr 是否变为了客户端真实 IP。
- 后端程序验证:创建测试文件直接打印获取到的 IP。
PHP 测试文件 (test_ip.php):
<?php
echo $_SERVER['REMOTE_ADDR'];
?>
Python Flask 测试片段:
from flask import request
@app.route('/ip')
def get_ip():
return request.remote_addr
Curl 命令测试:
curl -H "X-Forwarded-For: 1.2.3.4" http://your-server/test_ip.php
常见坑
- 信任范围过大:set_real_ip_from 如果配置为 0.0.0.0/0,任何用户都可以伪造 X-Forwarded-For 头冒充任意 IP,存在安全风险。
- Header 名称错误:不同代理传递的 header 不同,Cloudflare 常用 CF-Connecting-IP,普通 LB 常用 X-Forwarded-For,需根据实际情况调整 real_ip_header。
- 递归模式影响:real_ip_recursive 默认为 off。如果经过多层代理,可能需要开启 on 才能获取最原始客户端 IP,但需确保所有中间层都在信任列表中。
参考来源
- Nginx 官方文档:ngx_http_realip_module - https://nginx.org/en/docs/http/ngx_http_realip_module.html