应优先使用 map 指令预计算语言/ip 访问控制,统一置于 http 块顶层;将 allow/deny 移至 server 级别减少重复判断;结合 limit_req/limit_conn 做速率限制;敏感接口改用 jwt/oauth2 或 auth_request 外部鉴权。

直接用 if 判断语言或 IP 并做 deny/allow,看似简单,但容易拖慢请求处理速度。Nginx 的 if 指令在每次请求时都会执行,且不支持嵌套和复杂逻辑,频繁调用会增加 CPU 开销,尤其在高并发下影响明显。真正高效的做法是把访问控制逻辑前置、缓存化、轻量化。
优先用 map 指令预计算匹配结果
map 是 Nginx 中最轻量、最高效的条件映射机制,它在配置加载阶段就完成编译,在运行时仅做 O(1) 查表操作,几乎无性能损耗。
- 用
map $http_accept_language $lang_allowed预先标记是否允许某语言访问,避免每个请求都解析 Accept-Language 字符串 - 用
map $remote_addr $ip_status将 IP 段映射为 “allow”/“deny”/“unknown”,替代多层 allow/deny 顺序匹配 - 所有
map块统一放在http块顶层,不嵌套在 location 中,确保一次初始化、全局复用
把 deny/allow 移到 server 或 http 级别,减少重复判断
location 块内每写一组 allow/deny,Nginx 就要按顺序逐条比对,直到命中或走到 deny all。若规则分散在多个 location 中,相同 IP 可能被反复检查多次。
- 将通用 IP 黑白名单统一收口到
server块顶部,用allow/deny+return 403快速拦截恶意流量 - 对需精细控制的路径(如 /admin),再用
map结合if ($lang_allowed = "no") { return 403; },避免在 location 内堆砌 allow/deny - 禁用
if ($remote_addr = xxx) { deny; }这类低效写法,改用map或 geo 模块
结合 limit_req 和 limit_conn 做速率兜底,而非只靠 deny
单纯靠 deny all 拦截异常请求,无法应对扫描、爆破等高频低频混合攻击。而 limit_req 和 limit_conn 基于共享内存 zone 实现,底层使用红黑树+滑动窗口,查询和更新都是 O(log n),性能远高于字符串匹配。
- 为登录接口单独设
limit_req zone=login burst=5 nodelay,防暴力尝试 - 用
limit_conn perip 10控制单 IP 并发连接数,比在每个 location 里写 if 更稳定 - zone 名称尽量简短(如
apirate而非api_rate_limit_per_minute),减少哈希计算开销
慎用 auth_basic,必要时用外部认证服务分流
auth_basic 依赖每次请求读取 htpasswd 文件并做明文比对,文件大或并发高时易成瓶颈。更糟的是,它无法与 map、limit_req 等模块组合优化。
- 敏感后台(如 /dashboard)改用 JWT 或 OAuth2 验证,由后端或专用认证服务(如 Authelia)处理
- 若必须用基础认证,将 htpasswd 文件放在内存文件系统(如 tmpfs)中,减少磁盘 I/O
- 搭配
auth_request指令,把鉴权逻辑交给轻量 HTTP 服务,Nginx 只做代理和结果判断











