Nginx如何结合set_real_ip_from仅允许指定子网访问?
问题分析与解决方案
核心问题:指令执行顺序误解
你的两次尝试失败,根源都是没搞清楚Nginx中real_ip模块与访问控制指令的执行顺序:
real_ip相关指令(set_real_ip_from、real_ip_header等)会在访问控制阶段(allow/deny、geo变量计算)之前执行,直接替换$remote_addr为客户端真实IP。- 第一次尝试中,
allow/deny检查的是已经被替换后的客户端IP,而非代理出口IP,自然全部被拒绝;第二次尝试的geo模块默认匹配$remote_addr,同样拿到的是客户端真实IP,无法实现代理子网的访问限制。
正确配置思路
要同时实现「仅允许代理出口IP访问」和「获取客户端真实IP」,需要:
- 保留原始的代理出口IP(即
real_ip替换前的$remote_addr); - 基于原始代理IP完成访问控制;
- 控制逻辑生效后,再用
real_ip模块替换出客户端真实IP供后续业务处理。
Nginx的real_ip模块会自动将替换前的原始IP保存到$realip_remote_addr变量中,我们可以直接利用这个变量实现精准控制。
示例配置
http { # 1. 配置真实IP替换规则:仅信任指定代理子网的真实IP传递 set_real_ip_from 192.168.1.0/24; # 替换为你的代理出口IP子网 real_ip_header X-Forwarded-For; # 根据前端代理实际传递的真实IP头调整(如X-Real-IP) real_ip_recursive on; # 多层代理场景下开启,避免误将中间代理IP识别为真实IP # 2. 基于原始代理IP($realip_remote_addr)定义允许访问的子网 geo $realip_remote_addr $allow_proxy_access { default 0; 192.168.1.0/24 1; # 允许的代理出口子网 10.0.0.0/8 1; # 可添加多个子网 } server { listen 80; server_name your-site.com; # 3. 拦截非允许的代理IP请求 if ($allow_proxy_access != 1) { return 403; } location / { # 此时$remote_addr已替换为客户端真实IP,可用于后续业务处理 proxy_pass http://your-backend-service; # 传递真实IP给后端 proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; } } }
关键细节说明
geo $realip_remote_addr $allow_proxy_access:明确指定geo模块基于原始代理IP($realip_remote_addr)进行匹配,完全不受real_ip替换的影响;real_ip_recursive on:如果前端代理还有上层代理,开启这个参数可以让Nginx从X-Forwarded-For中解析出最原始的客户端IP,而非直接取列表第一个IP;- 访问控制逻辑放在
server块最前面,确保非允许请求被尽早拦截,减少不必要的资源消耗。
内容的提问来源于stack exchange,提问作者theKorzh
相关产品推荐
相关产品推荐

