IT

Nginx 限制单 IP 并发与请求速率防 CC 实战

AI智能摘要

Nginx 防 CC 不用装插件,limit_conn 和 limit_req 两个模块就够。本文给出共享内存区定义、server 级限流配置、burst 与 nodelay 的含义,还有日志验证和阈值建议,照着改完 nginx -t 重载即可生效。

防 CC 的核心思路其实就两条:把单个 IP 同时挂在服务器上的连接数压下去,再把它的请求频率压下去。Nginx 自带的 limit_conn 和 limit_req 两个模块就能干这事,不需要额外装东西。下面直接给配置和验证方法。

一、先确认模块,再定义共享内存区

执行 nginx -V 2>&1 | grep -o 'with-http_limit_conn_module|with-http_limit_req_module',两个都出现说明可用。绝大多数发行版编译时默认带上。

然后定义限流用的共享内存区,放在 http 块里:

http {
    # 以客户端 IP 为 key,记录并发连接数,10MB 约存 16 万个 IP
    limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
    # 以客户端 IP 为 key,记录请求速率,10MB 同样约 16 万个 IP
    limit_req_zone $binary_remote_addr zone=perip_req:10m rate=10r/s;
}

注意用的是 $binary_remote_addr 而不是 $remote_addr,前者是二进制定长(IPv4 占 4 字节),内存占用小得多,别写错。

二、在 server / location 里落地限制

把限制加到需要保护的站点或接口上:

server {
    listen 80;
    server_name example.com;

    # 单 IP 最多 20 个并发连接
    limit_conn perip_conn 20;
    # 单 IP 请求速率 10r/s,突发队列 20,超出直接拒绝
    limit_req zone=perip_req burst=20 nodelay;

    location / {
        root /var/www/html;
    }

    # 静态资源可以放宽,避免误伤正常用户
    location ~* .(jpg|png|css|js)$ {
        limit_conn perip_conn 50;
        limit_req zone=perip_req burst=50 nodelay;
    }
}

几个参数说清楚:burst=20 是允许瞬时排队 20 个请求,nodelay 表示这 20 个立即放行而不按 rate 平滑处理,否则用户会感觉明显卡顿。如果你要严格限速,就去掉 nodelay,但要接受延迟。

被拒绝时默认返回 503。想改成 429 更语义化,加一行:

limit_req_status 429;
limit_conn_status 429;

三、日志与验证

日志级别调到 warn 才能看到限流记录:

# 在 http 块中
limit_req_log_level warn;
limit_conn_log_level warn;

# 在对应 server 的 access_log 中加变量
log_format limit '$remote_addr - $status req=$request reqtime=$request_time limit=$limit_req_status';
access_log /var/log/nginx/limit.log limit;

验证用 ab 或 wrk 压一下:

ab -n 200 -c 50 http://example.com/

如果配置生效,日志里会出现 429(或 503),且 error.log 有 “limiting requests” 字样。压测时注意别从本机压本机,容易把 SSH 也限了,建议从另一台机器发起。

四、防 CC 的补充建议

  • 限流阈值别一刀切,先观察正常用户峰值再定。rate 设太小,公司出口 IP 下的员工会集体被限。
  • 对登录、短信验证码这类接口单独收紧,比如 limit_req zone=perip_req burst=5 nodelay;,比全站统一值更有效。
  • 结合 map 把已知搜索引擎 IP 段排除,避免误伤收录。
  • Nginx 限流是单机维度的,多台后端要各自配,或者在前置 LB 上统一做。真正的 CC 攻击建议再叠加云 WAF 或 CDN 的 IP 信誉库。
  • 改完配置先 nginx -t 再 nginx -s reload,别直接重启。

发表评论