在使用 nginx 作为反向代理或负载均衡器时,我们常常需要获取客户端的真实 ip 地址。然而,默认情况下,nginx 的 $remote_addr
变量记录的 ip 地址可能是上游代理或负载均衡器的 ip,而非实际客户端的 ip。为了确保我们能够正确获取和记录客户端的真实 ip,本文将介绍如何配置 nginx,并进行调试。
一、配置 nginx 获取客户端真实 ip
1、基本配置说明
首先,我们需要确保 nginx 能够正确解析来自上游代理或负载均衡器的 x-forwarded-for
头部信息。通过配置 real_ip_header
和 set_real_ip_from
,nginx 可以将 $remote_addr
更新为客户端的真实 ip。
示例配置:
http { include mime.types; default_type application/octet-stream; server_tokens off; # 设置真实 ip 的头部信息 real_ip_header x-forwarded-for; # 指定可信任的上游代理 ip 范围,这里以 172.0.0.0/8 为例(就是你负载均衡的ip网段) set_real_ip_from 172.0.0.0/8; # 其他配置 ... }
real_ip_header x-forwarded-for;
:指定从哪个头部获取客户端的真实 ip 地址。常见的头部包括x-forwarded-for
、x-real-ip
等。set_real_ip_from 172.0.0.0/8;
:指定哪些 ip 地址段的请求可以被信任。如果请求来自这些地址段,那么 nginx 会根据real_ip_header
的配置更新$remote_addr
。
在 nginx 中,set_real_ip_from
指令用于定义哪些 ip 地址或 ip 地址段是被信任的。根据请求来源 ip 地址是否在 set_real_ip_from
指定的范围内,nginx 的行为会有所不同,具体区别如下:
2、set_real_ip_from详解
1. 请求来源 ip 在 set_real_ip_from
范围内
如果请求来源的 ip 地址在 set_real_ip_from
指定的范围内,nginx 会信任该请求,并使用 real_ip_header
指定的头部(如 x-forwarded-for
)中的值作为客户端的真实 ip 地址。
行为:
- nginx 使用
x-forwarded-for
头中的第一个(最左边的)ip 地址作为$remote_addr
(即客户端的真实 ip 地址)。 - 这种情况通常出现在负载均衡器或反向代理服务器前端,它们会添加
x-forwarded-for
头来指示真实的客户端 ip。
2. 请求来源 ip 不在 set_real_ip_from
范围内
如果请求来源的 ip 地址不在 set_real_ip_from
指定的范围内,nginx 不会信任这个请求中的 x-forwarded-for
头部中的 ip 地址。
行为:
- nginx 直接使用请求来源的 ip 地址(即
$remote_addr
)作为客户端的 ip 地址。 - 这意味着 nginx 会将负载均衡器或代理服务器的 ip 地址视为客户端的 ip,而不会考虑
x-forwarded-for
头中的值。
场景分析:
-
在范围内: 如果你有一个负载均衡器,所有请求都会先经过它再到达 nginx。负载均衡器会在请求头中加入
x-forwarded-for
以记录客户端的真实 ip。如果你将负载均衡器的 ip 地址配置在set_real_ip_from
中,nginx 会读取并信任x-forwarded-for
中的客户端真实 ip。 -
不在范围内: 如果请求不是通过你信任的负载均衡器发来的(可能是直接访问 nginx,或者来自不可信的代理服务器),nginx 会认为这个请求中的
x-forwarded-for
不可信,于是使用实际请求来源 ip(负载均衡器或代理的 ip 地址)作为客户端 ip。
3、log_format 配置(参考)
配置日志格式时,可以直接使用 $remote_addr
变量。nginx 在解析 real_ip_header
后,会自动将 $remote_addr
替换为解析后的真实 ip 地址。
日志格式配置:
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
$remote_addr
:在配置了real_ip_header
之后,这个变量将代表客户端的真实 ip 地址。
二、调试与测试
为了确保配置正确,我们可以使用一个简单的调试日志来测试 x-forwarded-for
头部的内容。
添加调试日志
可以通过下面的配置,将 x-forwarded-for
头部记录到一个专门的调试日志文件中。
调试日志配置:
log_format debug '$http_x_forwarded_for'; access_log /path/to/log/debug.log debug;
通过这一配置,你可以在调试过程中直接查看 x-forwarded-for
头部的内容,以确认它是否包含客户端的真实 ip 地址。
检查调试日志
配置完成后,重启 nginx,并通过访问应用生成一些日志。然后,查看调试日志 /path/to/log/debug.log
以验证 x-forwarded-for
头部的值。
tail -f /path/to/log/debug.log
如果 x-forwarded-for
头部中包含了客户端的真实 ip 地址,那么说明配置正确,nginx 能够正确获取并记录客户端的真实 ip。
三、lua 中使用客户端真实 ip(参考)
在实际应用中,如果你使用了 openresty 或 nginx 的 lua 模块,可以在 lua 代码中使用 ngx.var.remote_addr
来获取解析后的真实 ip。
示例代码:
access_by_lua " local uid = ngx.var.cookie_bb_id if not uid then uid = ngx.md5(ngx.now() .. ngx.var.remote_addr .. ngx.var.http_user_agent) ngx.header['set-cookie'] = 'bb_id=' .. uid .. '; path=/; expires=' .. ngx.cookie_time(ngx.time() 3650*86400) .. '; secure; samesite=none' end ";
在上面的 lua 代码中,ngx.var.remote_addr
会获取到解析后的客户端真实 ip。这在用户跟踪或日志记录中非常有用。
四、总结
通过正确配置 real_ip_header
和 set_real_ip_from
,我们可以确保 nginx 能够通过 $remote_addr
获取并记录客户端的真实 ip 地址。在配置完成后,通过调试日志可以验证配置是否生效。如果你在 lua 中需要获取真实 ip,可以直接使用 ngx.var.remote_addr
。