白名单机制需先allow再deny all,且必须置于server或location块中;代理环境下须配置set_real_ip_from和real_ip_header获取真实IP;推荐用geo+if替代硬编码以提升灵活性。

直接用 deny all 拒绝所有未知 IP,本质是构建白名单机制——不是“拦坏人”,而是“只放行已知可信来源”,其余一律 403。关键不在 deny all 本身,而在它前面必须有明确的 allow 规则,且顺序、作用域、真实 IP 获取都必须准确。
白名单结构:allow 必须在 deny all 前面
deny all 单独存在没有意义,它只是“兜底拒绝”。真正起作用的是它前面那些 allow 行:
- 每条
allow 192.168.5.20;或allow 2001:db8::/32;独立成行,支持 IPv4 单 IP、IPv4 网段(CIDR)、IPv6 地址或网段 - 允许多个来源?直接追加多行 allow 即可,Nginx 会逐行匹配,命中即停
-
deny all;必须放在所有 allow 之后,且是该 location 块中最后一条访问控制指令 - 漏掉 deny all,未匹配的请求默认放行,白名单完全失效
必须写对位置:只在 server 或 location 块里生效
allow/deny 指令只能出现在 http、server、location 这三个作用域中,其他地方(如 events、upstream、if 块内)写进去无效或报错:
- 推荐写在具体路径下,比如
location /admin/ { ... },避免误杀静态资源或健康检查接口 - 不要写在 if 判断块里,例如
if ($request_uri ~ "/api") { allow 1.2.3.4; }—— 语法不报错,但访问控制不执行 - 多个 location 共存时,每个 location 的访问控制独立生效,需分别配置
代理环境下必须处理真实 IP
如果 Nginx 前面有 CDN、SLB 或反向代理,$remote_addr 是代理节点 IP,不是用户真实 IP,allow/deny 就会全部失准:
- 确认上游是否透传
X-Forwarded-For或X-Real-IP头,且内容可信(需在代理层清洗) - 在 http 块中添加:
set_real_ip_from 203.208.60.0/24;(填你所用 CDN 的可信 IP 段)real_ip_header X-Real-IP;或real_ip_header X-Forwarded-For; - 漏掉
set_real_ip_from,就算写了real_ip_header也没用——Nginx 会忽略未授权来源的头信息
更稳妥的替代方案:用 geo + if 替代硬编码 allow/deny
当规则变多、需复用或要动态管理时,geo 模块更灵活可靠(也规避了 allow 不支持域名、不能 include 的限制):
- 在 http 块顶部定义:
geo $is_trusted { default 0; 192.168.10.0/24 1; 2001:db8::/32 1; } - 在 location 中判断:
if ($is_trusted = 0) { return 403; } - 配合
include /etc/nginx/ip_whitelist.conf;可把 IP 列表抽离为外部文件,便于脚本自动更新


















