realip 模块
realip 模块获取真实客户端 IP
code
实际网络架构:
真实用户 → CDN/负载均衡/代理 → Nginx → 后端应用
| | | |
真实IP 替换为自身IP 看到的是 需要知道
(1.2.3.4) (5.6.7.8) 代理IP 真实IP模块功能:
bash
# 没有 realip 模块:
remote_addr = 代理服务器IP (5.6.7.8)
# 丢失了真实客户端IP
# 启用 realip 模块后:
remote_addr = 真实客户端IP (1.2.3.4)
# 从 X-Forwarded-For 等头部提取模块的工作机制
IP替换流程
图表渲染中…
相关变量变化
nginx
处理前:
$remote_addr = 代理服务器IP (192.168.1.100)
$proxy_add_x_forwarded_for = "1.2.3.4, 192.168.1.100"
处理后(如果192.168.1.100是可信代理):
$remote_addr = 真实客户端IP (1.2.3.4)
$realip_remote_addr = 原remote_addr (192.168.1.100)三、核心配置指令详解
1. set_real_ip_from - 定义可信代理
code
# 语法
set_real_ip_from address | CIDR | unix:;
# 示例
http {
# 单个IP
set_real_ip_from 192.168.1.100;
# CIDR网段
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
# IPv6
set_real_ip_from 2001:0db8::/32;
# Unix socket
set_real_ip_from unix:;
# 所有地址(谨慎使用!)
# set_real_ip_from 0.0.0.0/0;
}2. real_ip_header - 指定头部字段
code
# 语法
real_ip_header field | X-Real-IP | X-Forwarded-For | proxy_protocol;
# 常用配置
http {
# 使用 X-Real-IP 头部(单个IP)
real_ip_header X-Real-IP;
# 使用 X-Forwarded-For 头部(IP链)
real_ip_header X-Forwarded-For;
# 使用代理协议(HAProxy等)
real_ip_header proxy_protocol;
# 自定义头部
real_ip_header CF-Connecting-IP; # Cloudflare
real_ip_header True-Client-IP; # Akamai
}3. real_ip_recursive - 递归解析模式
code
# 语法
real_ip_recursive on | off; # 默认 off
# 示例对比
http {
# 场景:X-Forwarded-For: 1.2.3.4, 192.168.1.100, 10.0.0.1
# 模式1: off (默认)
real_ip_recursive off;
# 取最后一个非可信代理IP = 192.168.1.100
# 模式2: on
real_ip_recursive on;
# 从右向左找第一个非可信代理IP = 1.2.3.4
# 跳过 10.0.0.1 和 192.168.1.100(如果是可信代理)
}四、完整配置示例
1. 基础配置
code
http {
# 定义可信代理
set_real_ip_from 192.168.1.0/24;
set_real_ip_from 10.0.0.0/8;
# 从X-Forwarded-For获取真实IP
real_ip_header X-Forwarded-For;
# 启用递归模式
real_ip_recursive on;
server {
listen 80;
location / {
# 记录真实IP
access_log /var/log/nginx/access.log;
# 日志中的$remote_addr现在是真实客户端IP
# 传递给后端应用
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://backend;
}
}
}2. 多级代理环境
code
http {
# 所有内部代理
set_real_ip_from 10.1.0.0/16; # 第一层代理
set_real_ip_from 10.2.0.0/16; # 第二层代理
set_real_ip_from 10.3.0.0/16; # 第三层代理
# Cloudflare CDN IP段
include /etc/nginx/conf.d/cloudflare-ips.conf;
real_ip_header CF-Connecting-IP; # Cloudflare专用头部
real_ip_recursive on;
# 验证配置
server {
listen 80;
location /debug {
# 显示所有IP相关信息
add_header Content-Type text/plain;
return 200 "
真实客户端IP: $remote_addr
原始连接IP: $realip_remote_addr
X-Forwarded-For: $http_x_forwarded_for
CF-Connecting-IP: $http_cf_connecting_ip
";
}
}
}3. Cloudflare 专用配置
code
# /etc/nginx/conf.d/cloudflare-ips.conf
# Cloudflare IPv4地址(需要定期更新)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
# Cloudflare IPv6地址
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
# 主配置
real_ip_header CF-Connecting-IP;
real_ip_recursive on;五、变量说明
1. realip 模块引入的变量
code
# 核心变量
$realip_remote_addr # 替换前的原始remote_addr(代理服务器IP)
$realip_remote_port # 原始remote_port
# HTTP头部相关(处理后的)
$http_x_real_ip # 处理后的X-Real-IP头部
$http_x_forwarded_for # 处理后的X-Forwarded-For头部2. 变量使用示例
code
log_format realip_log '真实IP:$remote_addr '
'代理IP:$realip_remote_addr '
'端口:$realip_remote_port '
'XFF:$http_x_forwarded_for '
'XRI:$http_x_real_ip';
server {
access_log /var/log/nginx/realip.log realip_log;
location / {
# 传递给后端
proxy_set_header X-Original-Remote-Addr $realip_remote_addr;
proxy_set_header X-Real-Client-IP $remote_addr;
}
}六、不同场景下的配置策略
场景1:单一反向代理
code
架构:客户端 → Nginx(代理) → 后端应用
http {
# 没有中间代理,无需realip模块
# $remote_addr 直接就是客户端IP
server {
listen 80;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://backend;
}
}
}场景2:Nginx + 上层代理
code
架构:客户端 → CDN/ELB → Nginx → 应用
http {
# 信任CDN/ELB的IP
set_real_ip_from 203.0.113.0/24;
# 从X-Forwarded-For获取
real_ip_header X-Forwarded-For;
real_ip_recursive on;
server {
location / {
# 现在$remote_addr是真实客户端IP
proxy_set_header X-Client-IP $remote_addr;
}
}
}场景3:复杂代理链
code
架构:客户端 → CDN → WAF → 负载均衡 → Nginx → 应用
X-Forwarded-For: client, cdn, waf, lb
http {
# 信任所有中间代理
set_real_ip_from cdn_ip_range;
set_real_ip_from waf_ip_range;
set_real_ip_from lb_ip_range;
real_ip_header X-Forwarded-For;
real_ip_recursive on; # 重要!
server {
# $remote_addr = 客户端IP
# $realip_remote_addr = 负载均衡IP
}
}七、安全注意事项
1. IP欺骗防护
code
http {
# ❌ 危险配置:信任所有
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
# 攻击者可以发送 X-Forwarded-For: 8.8.8.8
# 从而伪装成任何IP
# ✅ 安全配置:明确可信代理
set_real_ip_from 192.168.1.0/24;
set_real_ip_from 10.0.0.0/8;
# 只信任内部网络
}2. IP验证策略
code
# 验证真实IP的合法性
geo $real_ip_whitelist {
default 0;
# 允许的IP段
192.168.0.0/16 1;
10.0.0.0/8 1;
# 已知攻击IP
1.2.3.4 0;
5.6.7.8 0;
}
server {
location / {
# 检查IP是否在白名单
if ($real_ip_whitelist = 0) {
# 记录可疑访问
access_log /var/log/nginx/suspicious.log;
# 可返回错误或限制访问
# return 403;
}
}
}3. 日志完整性
code
http {
# 同时记录原始IP和真实IP
log_format complete '$remote_addr ($realip_remote_addr) - $remote_user '
'[$time_local] "$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'X-Forwarded-For: "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log complete;
}八、常见问题排查
问题1:realip 模块不生效
code
# 1. 检查模块是否加载
nginx -V 2>&1 | grep -o with-http_realip_module
# 应该有输出: with-http_realip_module
# 2. 检查配置语法
nginx -t
# 3. 测试配置
curl -H "X-Forwarded-For: 1.2.3.4" http://server/debug
# 查看返回的真实IP
# 4. 检查可信代理设置
# 确认代理服务器的IP在 set_real_ip_from 列表中问题2:获取到错误的IP
code
# 调试配置
server {
location /ipinfo {
default_type text/plain;
# 输出所有相关信息
echo "原始连接IP: $realip_remote_addr";
echo "当前remote_addr: $remote_addr";
echo "X-Forwarded-For: $http_x_forwarded_for";
echo "X-Real-IP: $http_x_real_ip";
echo "";
echo "可信代理列表:";
echo "set_real_ip_from 配置...";
# 检查递归模式
echo "real_ip_recursive: [需要检查配置]";
}
}问题3:多层代理IP顺序混乱
code
假设链路:Client → Proxy1 → Proxy2 → Nginx
X-Forwarded-For 头部变化:
1. Client → Proxy1:
X-Forwarded-For: 192.168.1.100(client)
2. Proxy1 → Proxy2:
X-Forwarded-For: 192.168.1.100, 10.0.1.1(proxy1)
3. Proxy2 → Nginx:
X-Forwarded-For: 192.168.1.100, 10.0.1.1, 10.0.2.1(proxy2)
配置建议:
set_real_ip_from 10.0.1.1; # proxy1
set_real_ip_from 10.0.2.1; # proxy2
real_ip_recursive on; # 从右向左找第一个非可信IP
# 结果:$remote_addr = 192.168.1.100九、性能优化建议
1. CIDR聚合
code
http {
# ❌ 低效:多个独立IP
set_real_ip_from 192.168.1.1;
set_real_ip_from 192.168.1.2;
set_real_ip_from 192.168.1.3;
# ...
# ✅ 高效:CIDR聚合
set_real_ip_from 192.168.1.0/24;
# 如果必须单个IP,考虑数量
# 每个set_real_ip_from都有查找开销
}2. GeoIP模块配合
code
# 使用GeoIP模块限制国家
http {
# 加载GeoIP模块
# --with-http_geoip_module
geoip_country /usr/share/GeoIP/GeoIP.dat;
# 只允许特定国家的代理
map $remote_addr $allow_proxy {
default 0;
# 只信任来自本国的代理
~^203\.0\.113\. $geoip_country_code;
~^198\.51\.100\. $geoip_country_code;
}
# 条件启用realip
set_real_ip_from 203.0.113.0/24;
set_real_ip_from 198.51.100.0/24;
# 根据来源国家决定是否处理
real_ip_header X-Forwarded-For;
# 注意:需要额外逻辑控制
}十、与proxy_protocol的配合
1. proxy_protocol 配置
code
# 启用proxy_protocol
server {
listen 80 proxy_protocol; # 启用proxy protocol
listen 443 ssl proxy_protocol; # HTTPS也启用
# 从proxy protocol获取真实IP
real_ip_header proxy_protocol;
set_real_ip_from 192.168.1.0/24; # 仍然需要信任代理
# 设置真实服务器端口
real_ip_recursive on;
}2. HAProxy + Nginx 组合
code
# HAProxy配置
frontend web
bind *:80
mode http
option forwardfor
# HAProxy发送PROXY协议
# Nginx配置
http {
set_real_ip_from 192.168.1.0/24; # HAProxy的IP
real_ip_header proxy_protocol;
server {
listen 80 proxy_protocol;
# 现在可以获取真实客户端IP
access_log /var/log/nginx/access.log;
}
}十一、最佳实践总结
最小权限原则
code
# 只信任必要的代理
set_real_ip_from 10.0.0.0/8; # 内部网络
set_real_ip_from 203.0.113.0/24; # 已知CDN
# 不要用 0.0.0.0/0明确头部来源
code
# 与上游代理协商使用哪个头部
real_ip_header X-Real-IP; # 单个IP,更安全
# 或
real_ip_header X-Forwarded-For; # IP链,需要递归模式启用递归模式
code
# 多层代理环境下必须启用
real_ip_recursive on;完整日志记录
code
# 记录原始IP和真实IP
log_format detailed '$remote_addr|$realip_remote_addr|$time_local|$request';定期更新IP列表
code
# 自动化更新Cloudflare IP
curl -s https://www.cloudflare.com/ips-v4 > /etc/nginx/cloudflare-ips-v4.conf
curl -s https://www.cloudflare.com/ips-v6 > /etc/nginx/cloudflare-ips-v6.conf
# 在Nginx配置中引用
include /etc/nginx/cloudflare-ips-v4.conf;
include /etc/nginx/cloudflare-ips-v6.conf;测试验证
code
# 创建测试端点
location /debug-ip {
add_header Content-Type text/plain;
return 200 "Client: $remote_addr\nOriginal: $realip_remote_addr";
}通过合理配置 realip 模块,可以确保在复杂的代理环境中准确获取客户端真实IP,同时维护系统的安全性和可追溯性。