Nginx 限制 IP 访问用 allow 和 deny

FreeGuideOnline 最新 2026-07-05

Nginx 限制 IP 访问:allow 与 deny 指令完全指南

在 Web 服务器管理中,控制谁能访问你的网站、管理后台或敏感接口至关重要。Nginx 提供了两个轻量级、高性能的模块指令 allowdeny 来实现基于客户端 IP 地址的访问控制,无需引入额外的防火墙或复杂的验证层。本教程将从零开始,帮助你理解并熟练运用这两个指令。

理解核心概念:访问控制顺序与继承

allowdeny 指令由标准 HTTP 模块 ngx_http_access_module 提供,该模块默认编译在内,无需额外安装。它们的工作方式类似白名单和黑名单,但执行逻辑严格遵循从上到下的顺序匹配

  • allow address | CIDR | unix: | all;:允许指定 IP 或网络范围访问。
  • deny address | CIDR | unix: | all;:禁止指定 IP 或网络范围访问。

当 Nginx 处理一个请求时,会按配置文件中编写的顺序依次检查 allowdeny 规则。一旦客户端的 IP 匹配到某一条规则,则立即执行对应的操作(放行或拒绝),并停止后续检查。因此,规则的书写顺序会直接影响最终效果

基础用法:保护敏感目录

最常见的场景是限制整个网站、特定路径或管理后台只能由特定的 IP 地址访问。

假设你的办公网络出口 IP 为 203.0.113.5,你希望 /admin 目录下的所有资源仅允许从该 IP 访问,其余全部拒绝。

location /admin {
    allow 203.0.113.5;
    deny all;
}

解析

  • 第一条 allow 203.0.113.5; 明确放行该 IP。
  • 第二条 deny all; 捕获所有未被前面规则匹配的请求(即其他所有 IP)并直接返回 403 Forbidden。

如果你希望允许一个内部网络段(例如 10.0.0.0/24)而拒绝特定某个捣乱的 IP(例如 10.0.0.66),可以这样写:

location /api {
    deny 10.0.0.66;
    allow 10.0.0.0/24;
    deny all;
}

逻辑顺序:先精确拒绝 10.0.0.66,然后放行同一网段内的其他机器,最后拒绝网段外的所有请求。如果将 deny 10.0.0.66 放在最后,它就不会生效,因为该 IP 会先被 allow 10.0.0.0/24 匹配并放行。

指令的作用域:http, server 与 location

allowdeny 可以编写在 httpserverlocation 块中,其作用域和继承关系如下:

1. http 块(全局控制)

http 块内定义的规则会应用于所有虚拟主机(server 块)和所有路径,除非被下层覆盖。

http {
    # 全局默认拒绝所有访问,然后按需在下面放行
    deny all;

    server {
        listen 80;
        server_name example.com;
        # 因为上方 http 块已全局拒绝,此处需显式放行
        allow 203.0.113.0/24;
        allow 198.51.100.1;
        deny all;
        ...
    }
}

2. server 块(站点级控制)

应用于特定虚拟主机。如果某个 server 块内没有写任何 allow/deny,则会继承上级(http 块)的规则。

server {
    listen 80;
    server_name intranet.example.com;
    allow 10.0.0.0/8;
    deny all;
    ...
}

3. location 块(路径级控制)

最精细的控制层。location 块会继承 server 块的规则,但你可以在 location 内部重新定义规则来覆盖或增强。

重要特性:当 location 中定义了新的 allow/deny 规则时,父级定义的规则在该 location 内会被完全忽略,只有当前 location 中的规则生效。

示例:整体站点对公网开放,但 /private 仅限内网。

server {
    listen 80;
    server_name public-site.com;

    # 整个站点默认允许所有访问
    allow all;

    location /private {
        # 该 location 内重新定义规则,父级的 allow all 不再起作用
        allow 192.168.1.0/24;
        deny all;
    }
}

支持的网络地址格式

除了常见的单 IP 和 CIDR 格式,还支持以下特殊值:

  • all:匹配所有地址。
  • IPv4 单地址192.168.1.1
  • IPv4 CIDR10.0.0.0/1610.0.0.0/255.255.0.0(两种掩码写法均支持)
  • IPv6 单地址2001:0db8::1
  • IPv6 CIDR2001:0db8::/32
  • Unix 域套接字unix: (极少使用)

处理被拒绝的请求:自定义错误页

当请求被 deny 拦截时,Nginx 默认返回 HTTP 状态码 403 Forbidden,并附带一个简单的默认错误页面。你可能希望返回一个更友好的页面或一个 JSON 提示。

可以在 serverlocation 上下文中使用 error_page 指令自定义 403 页面:

server {
    ...
    # 禁止访问的返回自定义 HTML
    error_page 403 /403.html;
    location = /403.html {
        root /usr/share/nginx/html;
        internal;
    }

    location /secure {
        allow 203.0.113.5;
        deny all;
    }
}

对于 API 接口,也可以直接返回 JSON:

location /api/internal {
    allow 10.0.0.0/24;
    deny all;

    # 自定义 403 返回 JSON
    error_page 403 = @denied;
    location @denied {
        default_type application/json;
        return 403 '{"error":"access denied","code":403}';
    }
}

进阶技巧与常见陷阱

1. 使用地图(map)动态控制

如果需要在多个 serverlocation 中复用同一套复杂的 IP 规则,建议将 allow/denymapgeo 模块结合,但简单场景下直接书写即可。

2. 与 satisfy 指令的相互作用

当配置了多种访问控制(例如 IP 限制 + HTTP 基本认证)时,satisfy 指令会决定它们的逻辑关系(allany)。默认 satisfy all; 表示所有条件必须同时满足。如果你设置了 IP 白名单,同时又配置了 auth_basic,那么即使 IP 在白名单内,也会要求输入密码。此时可设置 satisfy any;,意指 IP 满足 或者 密码满足即放行。

location /staging {
    allow 127.0.0.1;
    allow 203.0.113.0/24;
    deny all;

    auth_basic "Staging Area";
    auth_basic_user_file /etc/nginx/.htpasswd;

    satisfy any; # IP 在白名单内 或 密码正确即可访问
}

3. 实时生效与测试

修改完配置后,务必先执行语法检查,再重载 Nginx,避免因笔误导致服务中断。

sudo nginx -t
sudo nginx -s reload

测试时,可以从受限制 IP 外访问,预期返回 403;从允许 IP 访问,预期正常加载。

4. 注意 CDN 或反向代理环境

如果你的 Nginx 位于负载均衡器、CDN 或反向代理之后,直接获取到的客户端 IP 会是代理的 IP,而不是用户的真实 IP。此时 allow/deny 将作用于代理 IP,导致规则失效。

必须确保通过 ngx_http_realip_module 正确设置了真实 IP,例如:

set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

然后在 allow/deny 规则中使用经过还原的真实 IP。

完整配置示例

下面是一个典型的组合场景:一个公司内部使用的 GitLab 服务,要求办公网络可以无限制访问,同时允许两个外部顾问的固定 IP 访问,其余全部拒绝,并返回统一的 JSON 错误。

server {
    listen 443 ssl;
    server_name git.internal.net;

    # 真实 IP 还原(如果前方有其他代理)
    set_real_ip_from 172.16.0.0/12;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

    # 定义 403 错误返回 JSON
    error_page 403 = @blocked;
    location @blocked {
        default_type application/json;
        return 403 '{"code":403,"message":"IP not allowed"}';
    }

    location / {
        # 办公网络完整网段
        allow 203.0.113.0/24;
        # 外部顾问固定 IP
        allow 198.51.100.77;
        allow 203.0.114.20;
        # 拒绝其余所有
        deny all;

        proxy_pass http://gitlab_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

总结

  • allowdeny 是 Nginx 内置的轻量级 IP 访问控制手段。
  • 规则按顺序匹配,命中即停止,顺序至关重要。
  • 可在 httpserverlocation 不同层级生效,下层可覆盖上层。
  • 配合 error_page 可自定义拒绝时的响应。
  • 代理环境中务必结合 real_ip 模块使用,确保基于真实 IP 过滤。

掌握这两个指令后,你就能轻松实现地域限制、后台保护、内网服务隔离等常见需求,且性能开销极低。