https://www.alibabacloud.com/help/zh/cdn/user-guide/configure-custom-request-headers
客户端IP 1.1.1.1 -> 阿里云CDN 2.2.2.2 ->内部NGINX负载器3.3.3.3->Nginx后端4.4.4.4
real_ip_header X-Forwarded-For; # 指定真实IP头部,一般为X-Forwarded-For或X-Real-IP
real_ip_recursive off;
OFF: 从右向左只最多剥离一层信任层,先检查remote_addr,再检查real_ip_header是否为信任IP, 返回不信任
ON: 从右向左剥离所有信任层,返回不信任IP
real_ip_recursive示解
- 客户端 IP:
1.1.1.1
- CDN IP:
2.2.2.2
- 内部 LB IP:
3.3.3.3
- 后端 NGINX 接收到的原始
$remote_addr
是3.3.3.3
(即内部 LB 的 IP)。 X-Forwarded-For
头部内容:1.1.1.1, 2.2.2.2, 3.3.3.3
1. real_ip_recursive off
后端 NGINX 配置:
set_real_ip_from 3.3.3.3; # 信任内部 LB
real_ip_header X-Forwarded-For;
real_ip_recursive off;
图示:
请求路径: 1.1.1.1 (客户端) --> 2.2.2.2 (CDN) --> 3.3.3.3 (内部LB) --> 后端 NGINX
后端 NGINX 收到:
原始 $remote_addr = 3.3.3.3
X-Forwarded-For = "1.1.1.1, 2.2.2.2, 3.3.3.3"
信任列表 (set_real_ip_from):{ 3.3.3.3 }
real_ip_recursive = off
处理步骤:
1. 检查原始 $remote_addr (3.3.3.3):在信任列表中。✅ 继续处理。
2. 处理 X-Forwarded-For 链 (从右往左):
"1.1.1.1, 2.2.2.2, [3.3.3.3]"
^
|
+-- 3.3.3.3 在信任列表。
由于 real_ip_recursive = off,只剥离这一层。
3. 剥离 3.3.3.3 后,链条变为:"1.1.1.1, 2.2.2.2"
^
|
+-- 将链中剩下的第一个IP (2.2.2.2) 设为 $remote_addr。
最终 $remote_addr = 2.2.2.2
2. real_ip_recursive on
示例图示
后端 NGINX 配置:
set_real_ip_from 3.3.3.3; # 信任内部 LB
set_real_ip_from 2.2.2.2; # 信任 CDN
real_ip_header X-Forwarded-For;
real_ip_recursive on;
图示:
请求路径: 1.1.1.1 (客户端) --> 2.2.2.2 (CDN) --> 3.3.3.3 (内部LB) --> 后端 NGINX
后端 NGINX 收到:
原始 $remote_addr = 3.3.3.3
X-Forwarded-For = "1.1.1.1, 2.2.2.2, 3.3.3.3"
信任列表 (set_real_ip_from):{ 2.2.2.2, 3.3.3.3 }
real_ip_recursive = on
处理步骤:
1. 检查原始 $remote_addr (3.3.3.3):在信任列表中。✅ 继续处理。
2. 处理 X-Forwarded-For 链 (从右往左,递归剥离):
a. "1.1.1.1, 2.2.2.2, [3.3.3.3]"
^
|
+-- 3.3.3.3 在信任列表。剥离。
b. 链条变为:"1.1.1.1, [2.2.2.2]"
^
|
+-- 2.2.2.2 在信任列表。剥离。
c. 链条变为:"[1.1.1.1]"
^
|
+-- 1.1.1.1 不在信任列表。停止剥离。
最终 $remote_addr = 1.1.1.1
NGINX负载器3.3.3.3
不经过CDN,直接请求源站,没有
http_Ali_Cdn_Real_Ip
,这里用map设置默认值为$remote_addr
http {
map $http_Ali_Cdn_Real_Ip $ali_cdn_real_ip {
default $remote_addr;
"~^(?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$" $ip;
}
server {
location / {
proxy_pass http://static.sundayhk.com;
proxy_set_header Host static.sundayhk.com;
proxy_set_header X-Real-IP $http_Ali_Cdn_Real_Ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
}
}
}
或者 http_x_forwarded_for,但要确保上游可信
http {
map $http_x_forwarded_for $real_ip {
default $remote_addr;
"~^(?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$" $ip;
"~^(?P<first_ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}),.*$" $first_ip; # return the first of one or more IPs
}
server {
location / {
proxy_pass http://static.sundayhk.com;
proxy_set_header Host static.sundayhk.com;
proxy_set_header X-Real-IP $real_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
}
}
}
NGINX后端4.4.4.4
server {
# 信任内部NGINX负载器IP, 因为会先检查上游再检查X-Real-IP是否信任
set_real_ip_from 3.3.3.3;
real_ip_header X-Real-IP;
real_ip_recursive off;
}
后端代码直接使用X-Real-IP做客户端IP, 虽然提取X-Forwarded-For第一位也可以实现,但不安全,因为它可以伪造。
后端NGINX 4.4.4.4 日志
# CDN过来
1.1.1.1 - - [27/Jul/2025:22:37:08 +0800] "GET /login HTTP/1.1" 200 85 "-" "Uptime-Kuma/1.23.16" "1.1.1.1, 2.2.2.2" 0.023 0.023 127.0.0.1:9000 200 -
# 请求源站,不经过CDN
1.1.1.1 - - [27/Jul/2025:22:37:16 +0800] "GET /login HTTP/1.1" 200 85 "-" "Uptime-Kuma/1.23.16" "1.1.1.1" 0.021 0.021 127.0.0.1:9000 200
real_ip_header X-Forwarded-For + real_ip_recursive on;
这种方式需要set_real_ip_from 信任所有负载器IP段和CDN IP段
set_real_ip_from 2.2.2.0/24; # 信任CDN回源所有IP段
set_real_ip_from 3.3.3.0/24; # 信任内部NGINX负载器
real_ip_header X-Forwarded-For;
real_ip_recursive on;