网站日志里如果突然出现大量 404、400,常见原因不是正常用户点错链接,而是自动扫描器在探测 .env、.git、wp-admin、phpmyadmin、xmlrpc.php 这类路径。
这类请求会带来几个问题:
- access log 被快速刷大
- 错误日志里充满无意义记录
- 静态站点或反代服务被大量无效请求占用连接
- 真正的问题被扫描噪音淹没
Nginx 可以用 limit_req 和 limit_conn 做限制。不过要先说明一点:Nginx 原生不能直接按“响应状态码是 404 或 400”再限速,因为限速发生在响应生成之前。
实际做法是:对容易产生 404 / 400 的扫描路径、异常来源和全站高频请求提前限速。
基本思路
推荐先分成三层:
- 全站温和限速,避免单个 IP 高频刷站。
- 对常见扫描路径严格限速,并直接返回
404。 - 对单 IP 并发连接数做限制。
更稳妥的上线顺序是:先加扫描路径规则和 access_log off,观察一天;如果还有大量随机路径 404,再加全站 limit_req。
先在 http 里定义限速池
limit_req_zone 和 limit_conn_zone 必须放在 http {} 里,不能放进单个站点的 server {}。
可以直接写到 /etc/nginx/nginx.conf 的 http {} 中:
|
|
也可以新建一个文件:
|
|
写入:
|
|
前提是你的 nginx.conf 里确实在 http {} 中包含了:
|
|
再在 server 里使用限速池
站点配置文件一般在 /etc/nginx/sites-enabled/www.example.com,里面通常是 server {}。这里不能再写 limit_req_zone,只能使用前面已经定义好的 zone。
示例:
|
|
如果担心全站限速误伤,可以先只加扫描路径这一段:
|
|
这些参数是什么意思
这一行:
|
|
含义如下:
limit_req_zone:定义请求限速用的计数池。$binary_remote_addr:按客户端 IP 做限速 key,比$remote_addr更省内存。zone=perip_general:20m:创建名为perip_general的共享内存区,大小为20m。rate=5r/s:每个 IP 平均每秒允许 5 个请求。
这一行:
|
|
和上面类似,只是更严格:
perip_scan:专门给疑似扫描路径使用。rate=1r/s:每个 IP 每秒只允许 1 个请求。
这一行:
|
|
含义如下:
limit_conn_zone:定义并发连接限制用的计数池。$binary_remote_addr:仍然按客户端 IP 统计。zone=addr_conn:20m:创建名为addr_conn的连接计数共享内存区。
真正限制并发连接数的是:
|
|
意思是:每个 IP 同时最多 20 个连接。
burst 和 nodelay 怎么理解
例如:
|
|
可以这样理解:
rate=5r/s:长期平均速率是每秒 5 个请求。burst=30:允许短时间多出来 30 个请求。nodelay:超过平均速率但还没超过burst时,不排队等待,直接处理;超过burst才拒绝。
没有 nodelay 时,Nginx 会尝试把部分请求排队延迟处理。对普通网页来说,nodelay 通常更直观;对 API 或特别敏感的接口,可以按实际情况调整。
常见错误:limit_req_zone 放错位置
如果看到这样的报错:
|
|
意思就是:limit_req_zone 写进了不允许的位置。
常见错误写法是把它放在 server {} 里:
|
|
这不行。
一句话记忆:
limit_req_zone是“定义池子”,放http {}。limit_req是“使用池子”,放server {}或location {}。limit_conn_zone是“定义连接池子”,放http {}。limit_conn是“使用连接池子”,放server {}或location {}。
临时封禁明显异常 IP
如果日志里已经确认某几个 IP 持续刷请求,也可以先临时封掉:
|
|
这类 deny 可以放在 server {} 里,也可以放在具体 location {} 里。是否长期保留,要看误伤风险和访问来源。
检查并重载
改完先检查配置:
|
|
没有问题再重载:
|
|
不要直接重启服务。reload 会让 Nginx 平滑加载新配置,风险更小。
推荐参数
如果只是普通个人站点或静态站点,可以先用下面这组:
- 普通页面:
rate=5r/s到10r/s - 扫描路径:
rate=1r/s - 扫描路径
burst=5 - 全站
burst=30 - 单 IP 并发:
10到20
如果正常用户访问量很小,参数可以更严格;如果站点有大量图片、脚本、接口请求,普通页面限速要放宽一些,避免误伤真实访问。
最稳的处理方式是分阶段上线:
- 先对扫描路径
access_log off+return 404。 - 再加
perip_scan严格限速。 - 观察一天日志。
- 如果随机路径 404 仍然很多,再开启全站温和限速。