Nginx 配置 limit_req 抵御 CC 攻击报错 503 怎么优化?

文章导读
遇到 Nginx 因 limit_req 返回 503,通常意味着限流策略触发了拒绝机制,优化方向不是关闭限流,而是调整速率阈值和突发容忍度,同时区分正常流量与攻击特征。
📋 目录
  1. 命令速用版(含白名单配置)
  2. 为什么会这样
  3. 分步处理与 CC 特征识别
  4. 压测验证:具体的 curl 脚本
  5. 常见坑
  6. 参考来源
A A

遇到 Nginx 因 limit_req 返回 503,通常意味着限流策略触发了拒绝机制,优化方向不是关闭限流,而是调整速率阈值和突发容忍度,同时区分正常流量与攻击特征。

先说结论:503 是限流生效的正常表现,优化重点在于调整 burst 值和识别误伤,而非单纯消除报错

  • 先判断:确认 503 是来自 limit_req 模块而非后端服务不可用
  • 优先做:调整 burst 参数允许突发流量,避免正常用户被误拦
  • 再验证:通过 access 日志观察限流触发频率和状态码分布

命令速用版(含白名单配置)

以下配置展示了如何结合 map 模块实现 IP 白名单,并将限流作用域缩小到特定接口,避免全局误伤。

http {
    # 1. 定义白名单逻辑:可信 IP 的限流 key 设为空字符串
    map $remote_addr $limit_key {
        default $binary_remote_addr;
        192.168.1.0/24 "";
        10.0.0.1 "";
    }

    # 2. 使用变量作为 zone 的 key
    limit_req_zone $limit_key zone=one:10m rate=10r/s;

    server {
        # 3. 建议只对动态接口限流,避免影响静态资源
        location /api/ {
            limit_req zone=one burst=20 nodelay;
            limit_req_status 429;
        }
    }
}

注意:尽量避免在 location / 全局开启严格限流,否则可能误伤所有接口包括静态资源。白名单 IP 的 key 设为空字符串 "" 可使其绕过限流。

为什么会这样

limit_req 模块使用漏桶算法(leaky bucket algorithm)控制请求速率。当请求超过设定的 rate 且超出 burst 缓冲容量时,Nginx 会直接拒绝请求。默认情况下,被拒绝的请求会返回 503 Service Unavailable 状态码。这在防御 CC 攻击时是预期行为,但如果配置过严,正常用户高峰访问也会触发 503。

Nginx 配置 limit_req 抵御 CC 攻击报错 503 怎么优化?

分步处理与 CC 特征识别

1. 确认报错来源:检查 error.log,搜索 limit_req 关键字,确认 503 是由限流模块产生,而不是 upstream 后端服务返回。

2. 调整突发容量:在 limit_req 指令中增加 burst 参数。例如 rate=10r/s 时,设置 burst=20,允许短时间内突发请求排队处理。

3. 优化处理策略:添加 nodelay 参数,让 burst 内的请求立即处理而不是延迟,减少用户等待感。

4. 自定义状态码:使用 limit_req_status 指令将 503 改为 429 Too Many Requests,便于监控区分是限流还是服务故障。

5. 识别 CC 攻击特征:正常用户通常有完整的 User-Agent 且访问频率分散,CC 攻击往往 UA 缺失或单一 IP 高频访问。可结合日志分析:

Nginx 配置 limit_req 抵御 CC 攻击报错 503 怎么优化?
grep "limit_req" /var/log/nginx/error.log | awk '{print $8}' | sort | uniq -c | sort -nr

压测验证:具体的 curl 脚本

使用以下 shell 脚本模拟高频请求,观察返回状态码。如果配置生效,超过 burst 限制的请求应返回 429。

for i in {1..50}; do curl -I -o /dev/null -s -w "%{http_code}\n" http://your-domain.com/api/test; done

同时 tail -f access.log,查看状态码列是否出现 429 或 503。如果调整 burst 后,正常访问不再出现限流状态码,而高频攻击请求仍被拦截,说明配置生效。

常见坑

1. NAT 环境误伤:多个用户共用出口 IP 时,严格限流会导致正常用户无法访问,需结合 cookie 挑战或_js 验证。

2. 静态资源限流:对 css、js、图片等静态文件开启严格限流会影响页面加载,建议只对动态接口启用。

Nginx 配置 limit_req 抵御 CC 攻击报错 503 怎么优化?

3. 状态码语义:改为 429 虽便于识别,但搜索引擎或部分客户端可能仍期待 503,修改前需确认业务兼容性。

4. 内存消耗:limit_req_zone 需要共享内存,zone 大小设置过小可能导致无法记录足够 IP,设置过大浪费内存。

5. 白名单配置错误:确保 map 模块定义在 http 块内,且空字符串使用双引号包裹,否则可能生效失败。

参考来源

1. Nginx 官方文档 - ngx_http_limit_req_module
URL: http://nginx.org/en/docs/http/ngx_http_limit_req_module.html