Nginx 限流防刷完全指南从原理到生产实战指南

 更新时间:2026年05月06日 10:11:09   作者:0xDevNull  
本文给大家介绍Nginx限流防刷完全指南从原理到生产实战指南,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

一、核心原理

Nginx 提供两个核心模块实现限流,各司其职:

模块功能算法/机制适用场景
ngx_http_limit_req_module限制单个 IP 在单位时间内的请求数量漏桶算法防刷接口、控制 QPS
ngx_http_limit_conn_module限制单个 IP 同时建立的连接数量连接计数防 CC 攻击、防连接耗尽

漏桶算法:以固定速率处理请求,超出速率的请求排队或被拒绝。burst 定义桶容量,nodelay 决定是否延迟处理。

二、环境准备

系统要求:Ubuntu 20.04 / CentOS 7+,Nginx ≥ 1.1.8(当前稳定版均支持)。

# Ubuntu
sudo apt update && sudo apt install nginx -y
# CentOS
sudo yum install epel-release -y && sudo yum install nginx -y

确认模块已编译

nginx -V 2>&1 | grep -o with-http_limit_req_module
nginx -V 2>&1 | grep -o with-http_limit_conn_module

三、基础配置:限制单 IP 请求速率

3.1 定义限流区域(http 块)

http {
    # 按客户端IP限流,10MB共享内存(约存16万IP),每秒10个请求
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
    # 登录接口专用:更严格的限制
    limit_req_zone $binary_remote_addr zone=login_limit:5m rate=2r/s;
    # 并发连接限制
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}

为什么用 $binary_remote_addr 而非 $remote_addr? 二进制格式更省内存,推荐生产环境使用。

3.2 应用限流规则(server/location 块)

server {
    listen 80;
    server_name api.example.com;
    location /api/ {
        # 应用限流:允许突发20个请求,nodelay立即处理突发,超出部分直接拒绝
        limit_req zone=api_limit burst=20 nodelay;
        # 自定义限流返回状态码(429比默认503更符合语义)
        limit_req_status 429;
        proxy_pass http://backend_server;
    }
    location /api/login {
        # 登录接口使用更严格的限流
        limit_req zone=login_limit burst=5 nodelay;
        limit_req_status 429;
        proxy_pass http://auth_service;
    }
}

参数深度解析

  • rate=10r/s:这是长期的平均速率,也可写 30r/m(每分钟30次)
  • burst=20:当请求瞬间超过 10r/s 时,多出来的请求会先进入“突发桶”排队。
  • nodelay:加上这个参数,突发桶里的 20 个请求会立即被处理,而不是按每秒 10 个的速度排队。如果不加 nodelay,请求会被延迟处理,适合对实时性要求不高的场景。

四、组合防护:速率 + 连接双限制

生产环境推荐同时启用双重保护:

http {
    # 速率限制区
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=50r/s;
    # 连接数限制区
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
    server {
        location /api/ {
            proxy_pass http://backend_server;
            # 速率限制:每秒50个,允许突发100个
            limit_req zone=api_limit burst=100 nodelay;
            # 连接数限制:单个IP最多同时保持50个连接
            limit_conn conn_limit 50;
            limit_conn_status 429;
        }
    }
}

五、精细化限流策略

5.1 按接口路径限流(防扫描)

防止扫描器遍历 API,对每个 URI 单独计数:

http {
    # $uri 不包含查询参数,如需区分参数用 $request_uri
    limit_req_zone $uri zone=per_uri:10m rate=10r/s;
}
server {
    location / {
        limit_req zone=per_uri burst=20 nodelay;
        limit_req_status 429;
        proxy_pass http://backend;
    }
}

5.2 动态分级限流(VIP用户)

通过 map 实现不同用户等级的差异化限流:

http {
    # 从请求头获取用户等级(需后端传递)
    map $http_x_user_level $rate_limit {
        "vip"     "100r/s";
        "normal"  "10r/s";
        default   "2r/s";
    }
    limit_req_zone $binary_remote_addr zone=dynamic:10m rate=$rate_limit;
    server {
        location /api/ {
            limit_req zone=dynamic burst=5 nodelay;
            proxy_pass http://backend;
        }
    }
}

注:rate 使用变量需 Nginx 1.15.10+。

5.3 下载限速 + 并发限制

location /download/ {
    limit_conn conn_limit 2;      # 单IP最多2个并发下载
    limit_rate 500k;              # 单连接限速500KB/s
    alias /data/files/;
}

5.4针对敏感接口

登录和验证码接口是暴力破解的重灾区,需要设置更严格的规则:

http {
    # 专门为登录接口定义一个更严格的限流区:每秒仅允许 2 次请求
    limit_req_zone $binary_remote_addr zone=login_limit:5m rate=2r/s;
    server {
        # 普通接口
        location /api/ {
            limit_req zone=api_limit burst=50 nodelay;
            proxy_pass http://backend_server;
        }
        # 登录接口(单独配置)
        location /api/login {
            limit_req zone=login_limit burst=5 nodelay;
            limit_req_status 429;
            proxy_pass http://backend_server;
        }
    }
}

六、白名单与动态控制

6.1 白名单配置(geo + map 技巧)

Nginx 的 limit_req 不能直接通过 if 开关,需用 zone 切换实现"跳过限制":

http {
    # 定义白名单
    geo $whitelist {
        default 0;
        203.0.113.0/24 1;    # 公司出口IP段
        192.168.1.100 1;
    }
    # 正常限流区
    limit_req_zone $binary_remote_addr zone=global:10m rate=20r/s;
    # 虚拟高速区(白名单IP使用,实际不限流)
    limit_req_zone $binary_remote_addr zone=dummy:1m rate=10000r/s;
    # 根据白名单动态选择zone
    map $whitelist $limit_zone {
        1 "dummy";
        0 "global";
    }
    # 登录专用区
    limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
    map $whitelist $login_zone {
        1 "dummy";
        0 "login";
    }
    # 并发限制
    limit_conn_zone $binary_remote_addr zone=connip:10m;
    # 日志格式增加限流信息
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" limit_req_status=$limit_req_status';
    server {
        listen 80;
        server_name api.example.com;
        access_log /var/log/nginx/api_access.log main;
        limit_req_status 429;
        limit_conn_status 429;
        # 全局接口
        location / {
            limit_req zone=$limit_zone burst=30 nodelay;
            limit_conn connip 20;
            proxy_pass http://backend;
        }
        # 登录接口
        location /api/login {
            limit_req zone=$login_zone burst=3 nodelay;
            proxy_pass http://auth;
        }
        # 下载接口
        location /download/ {
            limit_conn connip 2;
            limit_rate 500k;
            alias /data/downloads/;
        }
    }
}

七、CDN / 反向代理场景

如果 Nginx 前有 CDN 或 NAT,需获取真实客户端 IP:

# 配置真实IP来源
set_real_ip_from 10.0.0.0/8;      # CDN节点网段
set_real_ip_from 172.16.0.0/12;
real_ip_header X-Forwarded-For;
# 使用真实IP限流
limit_req_zone $http_x_forwarded_for zone=cdn_limit:10m rate=20r/s;

八、友好的限流提示

自定义 429 错误页面,返回 JSON:

server {
    # 自定义限流错误
    error_page 429 = @rate_limited;
    location @rate_limited {
        default_type application/json;
        return 429 '{"code": 429, "msg": "请求过于频繁,请稍后再试"}';
    }
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
        limit_req_status 429;
        proxy_pass http://backend;
    }
}

九、测试与验证

9.1 ApacheBench (ab)

# 安装
sudo apt install apache2-utils   # Ubuntu
sudo yum install httpd-tools      # CentOS
# 发送100个请求,并发10个
ab -n 100 -c 10 http://api.example.com/api/test

9.2 curl 循环测试

for i in {1..100}; do
    http_code=$(curl -s -o /dev/null -w "%{http_code}" http://api.example.com/api/test)
    echo "Request $i: $http_code"
done

9.3 日志排查

# 实时查看限流日志
tail -f /var/log/nginx/error.log | grep "limiting requests"
# 统计429状态码数量
grep " 429 " /var/log/nginx/access.log | wc -l
# 查看限流状态(若配置了日志格式)
tail -f /var/log/nginx/api_access.log

十、进阶优化

10.1 调整日志级别

limit_req_log_level error;    # 默认warn,可选info/notice/warn/error
limit_conn_log_level error;

10.2 结合 Fail2ban 自动封禁

配置 Fail2ban 监控 429 日志,超限直接 iptables 封禁:

# /etc/fail2ban/jail.local
[nginx-req-limit]
enabled  = true
filter   = nginx-req-limit
action   = iptables-multiport[name=ReqLimit, port="http,https"]
logpath  = /var/log/nginx/api_access.log
maxretry = 10
findtime = 60
bantime  = 600
# /etc/fail2ban/filter.d/nginx-req-limit.conf
[Definition]
failregex = ^<HOST> -.* 429
ignoreregex =

10.3 平滑重载配置

sudo nginx -t && sudo systemctl reload nginx

十一、完整生产配置示例

http {
    # ========== Zone 定义 ==========
    limit_req_zone $binary_remote_addr zone=global:20m rate=20r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
    limit_req_zone $binary_remote_addr zone=dummy:1m rate=10000r/s;
    limit_conn_zone $binary_remote_addr zone=connip:10m;
    # ========== 白名单 ==========
    geo $whitelist {
        default 0;
        203.0.113.0/24 1;
    }
    map $whitelist $limit_zone {
        1 "dummy";
        0 "global";
    }
    map $whitelist $login_zone {
        1 "dummy";
        0 "login";
    }
    # ========== 日志 ==========
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" limit_req_status=$limit_req_status';
    server {
        listen 80;
        server_name api.example.com;
        access_log /var/log/nginx/api_access.log main;
        limit_req_status 429;
        limit_conn_status 429;
        # 全局API
        location /api/ {
            limit_req zone=$limit_zone burst=30 nodelay;
            limit_conn connip 20;
            proxy_pass http://backend;
        }
        # 登录(更严格)
        location /api/login {
            limit_req zone=$login_zone burst=3 nodelay;
            proxy_pass http://auth;
        }
        # 下载
        location /download/ {
            limit_conn connip 2;
            limit_rate 500k;
            alias /data/downloads/;
        }
        # 限流提示
        error_page 429 = @rate_limited;
        location @rate_limited {
            default_type application/json;
            return 429 '{"code":429,"msg":"请求过于频繁,请稍后再试"}';
        }
    }
}

十二、关键注意事项

要点说明
共享内存大小10MB 约存16万IP,日活大需调大
burst + nodelay不加 nodelay 会延迟排队,加则直接丢弃超限请求
CDN/代理必须配置 real_ip_header 获取真实IP,否则误伤
阈值调优根据后端实际抗压能力和正常用户习惯动态调整
限流非目的本质是为后端争取恢复空间,需配合监控和自动封禁

通过合理组合 limit_reqlimit_conn,配合白名单、分级限流、友好提示和 Fail2ban 联动,可以为 API 构建一道低成本、高效率的防护墙。

到此这篇关于Nginx 限流防刷完全指南从原理到生产实战指南的文章就介绍到这了,更多相关nginx 限流防刷内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Nginx的超时keeplive_timeout配置步骤

    详解Nginx的超时keeplive_timeout配置步骤

    Nginx 处理的每个请求均有相应的超时设置,本文主要介绍了Nginx的超时keeplive_timeout配置步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • WebApi部署多服务器配置Nginx负载均衡的教程

    WebApi部署多服务器配置Nginx负载均衡的教程

    这篇文章主要介绍了WebApi部署多服务器配置Nginx负载均衡 ,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • Linux下安装nginx的实现方法

    Linux下安装nginx的实现方法

    这篇文章主要介绍了Linux下安装nginx的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-04-04
  • nginx配置指令之server_name的具体使用

    nginx配置指令之server_name的具体使用

    本文主要介绍了nginx配置指令之server_name的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • 如何配置nginx作为静态文件托管服务器

    如何配置nginx作为静态文件托管服务器

    这篇文章主要介绍了如何配置nginx作为静态文件托管服务器的相关资料,下载nginx在windows上是个压缩包,解压后,使用命令行输入nginx进行启动,感兴趣的朋友跟随小编一起看看吧
    2024-01-01
  • Nginx 解决WebApi跨域二次请求以及Vue单页面的问题

    Nginx 解决WebApi跨域二次请求以及Vue单页面的问题

    下面小编就为大家分享一篇Nginx 解决WebApi跨域二次请求以及Vue单页面的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • nginx中斜杠(‘/‘)的具体使用

    nginx中斜杠(‘/‘)的具体使用

    在Nginx配置的过程中,斜杠(/)经常使用到,它们不仅可以区分不同的路径,还有其他的作用,本文就详细的介绍了nginx中斜杠(‘/‘)的具体使用,感兴趣的可以了解一下,感兴趣的可以了解一下
    2023-10-10
  • nginx升级到支持HTTP2.0的方法示例

    nginx升级到支持HTTP2.0的方法示例

    这篇文章主要介绍了nginx升级到支持HTTP2.0的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • 503 service unavailable错误解决方案讲解

    503 service unavailable错误解决方案讲解

    这篇文章主要介绍了503 service unavailable错误解决方案讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Keepalived+Nginx+Tomcat 实现高可用Web集群的示例代码

    Keepalived+Nginx+Tomcat 实现高可用Web集群的示例代码

    这篇文章主要介绍了Keepalived+Nginx+Tomcat 实现高可用Web集群的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09

最新评论