在复杂的网络架构中,Nginx通常作为反向代理或网关部署在最前端,负责接收客户端的请求并转发给后端的业务服务器。这种架构虽然提升了系统的并发处理能力和安全性,但也引入了一个显著的问题:后端服务器接收到的请求源IP地址不再是真实客户端的IP,而是Nginx服务器的内网IP。这种情况会导致后端应用在进行风控审计、地域统计、频率限制等操作时失效。为了解决这个回源问题,我们需要在Nginx层面获取并透传真实客户端IP,通常通过True-Client-IP或X-Forwarded-For请求头来实现。

Nginx反向代理中的IP丢失问题与原理解析
当客户端直接访问后端服务器时,TCP连接建立后,服务器可以通过系统调用获取到对端的IP地址。然而,当架构中引入Nginx作为反向代理后,TCP连接被拆分为两段:客户端到Nginx的连接,以及Nginx到后端服务器的连接。后端服务器看到的TCP源IP实际上是Nginx的IP。如果不做特殊处理,后端应用将永远无法知道真正发起请求的用户是谁。
为了弥补这一缺陷,HTTP协议层面引入了X-Forwarded-For(简称XFF)请求头。Nginx在转发请求时,可以将客户端的真实IP追加到XFF头中发送给后端。但是,XFF头是一个可读写的字段,中间经过的任何代理都可以修改它,如果客户端直接伪造一个XFF头发送给Nginx,Nginx默认会将其原样透传,这就带来了安全隐患。
为了更规范地传递真实IP,True-Client-IP请求头应运而生。这个头部通常由网络拓扑中最外层、最受信任的代理服务器(如CDN或入口Nginx)强制写入。与XFF不同,True-Client-IP只包含一个IP地址,即真实客户端的IP。后端服务器只需读取该头部即可获得真实IP,同时可以结合配置忽略掉请求中自带的伪造True-Client-IP头部,从而保证数据的准确性。
配置Nginx透传真实客户端IP到后端
要让后端服务器能够获取到真实IP,必须在Nginx的配置文件中使用proxy_set_header指令。对于True-Client-IP,我们需要明确将其设置为Nginx接收到的客户端IP变量。在Nginx中,$remote_addr变量代表了直接连接Nginx的客户端IP。如果Nginx是入口层,那么这个变量就是真实用户IP。
下面是一个标准的反向代理配置示例,展示了如何向下游传递真实IP:
server {
listen 80;
server_name api.ipipp.com;
location / {
# 将真实客户端IP传递给后端
proxy_set_header True-Client-IP $remote_addr;
# 同时维护X-Forwarded-For链,兼容旧版应用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 传递主机名等其他信息
proxy_set_header Host $host;
proxy_pass http://backend_servers;
}
}
在上述配置中,proxy_set_header True-Client-IP $remote_addr;这行代码是核心。它强制覆盖了客户端可能携带的任何伪造的True-Client-IP头部,确保后端收到的值一定是Nginx认为的真实IP。同时,为了兼容那些只识别XFF的后端应用,我们依然保留了X-Forwarded-For的设置,其中$proxy_add_x_forwarded_for变量会自动将$remote_addr追加到现有的XFF字符串末尾。
如果Nginx不是最外层入口,而是位于CDN之后,那么$remote_addr获取到的将是CDN节点的IP。此时,我们需要使用Nginx的ngx_http_realip_module模块来从CDN传递的头部中提取真实IP,并重新赋值给$remote_addr。配置方法如下:
# 在http或server块中配置
set_real_ip_from 192.168.0.0/16; # 信任的CDN或上级代理IP段
real_ip_header True-Client-IP; # 从哪个头部提取真实IP
real_ip_recursive on;
server {
listen 80;
location / {
# 此时 $remote_addr 已经被替换为真实客户端IP
proxy_set_header True-Client-IP $remote_addr;
proxy_pass http://backend_servers;
}
}
优化Nginx日志格式以记录真实IP
仅仅将真实IP透传给后端是不够的,作为网关层,Nginx自身的访问日志也需要准确记录这个关键信息。默认的Nginx日志格式通常只记录$remote_addr,这在多层代理架构下是不够的。我们需要自定义log_format,将True-Client-IP和X-Forwarded-For一并记录,以便于后续的日志分析和问题排查。
在Nginx中,可以通过$http_true_client_ip和$http_x_forwarded_for变量来获取对应请求头的值。下面是一个扩展后的日志格式配置:
http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'true_client_ip=$http_true_client_ip '
'xff=$http_x_forwarded_for';
access_log /var/log/nginx/access.log main;
# ... 其他配置 ...
}
在这个日志格式中,我们不仅记录了直接连接者$remote_addr,还额外记录了true_client_ip和xff字段。当发生安全事件或需要排查特定用户行为时,运维人员可以通过这几个字段的对比来快速定位问题。例如,如果$remote_addr是内网代理IP,而true_client_ip显示为某个公网IP,说明请求经过了正常的代理链路;如果true_client_ip为空,则可能意味着上级代理未正确配置该头部的传递。
此外,在分析日志时需要注意X-Forwarded-For字段的特殊性。由于XFF是一个链式结构,每次经过代理都会追加一个IP,因此它的值可能类似于客户端IP, 代理1IP, 代理2IP。在编写日志分析脚本时,通常需要提取XFF字符串中的第一个IP地址作为真实客户端IP。而True-Client-IP由于只包含单一IP,处理起来更为简单直接,这也是在现代架构中推荐使用True-Client-IP进行回源的重要原因之一。
Nginx反向代理True-Client-IP真实IP修改时间:2026-08-26 19:27:06