2026 年 7 月 31 日,我在查看 EdgeOne 前一天的统计数据时,发现 www.shuijingwanwq.com 出现了一段非常异常的请求曲线。
正常情况下,网站每天的请求量相对平稳。但在 7 月 30 日下午,L7 请求数突然快速上涨,并持续了两个多小时。
最初我只是想确认这是不是一次普通的爬虫访问,后来通过 EdgeOne 指标、缓存状态、回源请求数和 Nginx 日志逐层排查,最终确认:
这是一次针对大量 PHP 文件路径的自动化扫描。异常期间约有 109 万次请求实际到达源站,其中约 108 万次针对 PHP 路径。
排查过程中还发现,服务器原有的 Nginx 限流配置在接入 EdgeOne 和 Cloudflare 后,已经不能按照真实客户端 IP 工作,反而可能对 CDN 回源节点进行限流。
本文记录完整的分析过程,以及最后采用的简化处理方案。
一、EdgeOne 请求数突然上涨
从 EdgeOne 的指标分析页面可以看到,2026 年 7 月 30 日出现了明显异常:
- L7 总请求数:188.41 万次
- L7 防护命中:63.87 万次
- Web 防护缓解请求:67.63 万次
- 未经防护缓解请求:120.79 万次
- L7 流量:4.76 GB
- 峰值带宽:4.33 Mbps
与前一个对比周期相比:
- 请求数上涨约 1180%
- 防护命中上涨超过 52000%
- 但总流量只上涨约 65%

这里最值得注意的是:
请求数上涨了十几倍,但传输流量并没有同步上涨。
这通常意味着新增请求的响应内容非常小,更像大量重复请求、路径扫描、恶意机器人或者 HTTP Flood,而不是正常用户集中浏览文章和图片。
二、将异常时间缩小到 15:00~18:30
为了避免当天其他正常请求干扰,我将统计时间调整为:
2026 年 7 月 30 日 15:00~18:30
在这个时间范围内,EdgeOne 显示:
- L7 请求:177.68 万次
- Web 防护缓解:67.63 万次
- 未经缓解:110.06 万次
- L7 流量:2.72 GB
从曲线看,异常流量大约在 15:50 后开始上升,到 18:20 左右结束。
后来结合 Nginx 日志进一步确认,真正的异常时间为:
15:58 左右开始,16:00 全面爆发,18:23 结束。
18:23 时每分钟仍有超过 1.1 万次请求,到了 18:24,直接恢复到每分钟 26 次。
这种突然开始、持续运行、然后突然停止的特征,也非常符合自动化扫描任务。
三、接近一半的请求返回 404
状态码统计显示:
| 状态码 | 请求数 |
|---|---|
| 404 | 92.85 万 |
| 200 | 68.70 万 |
| 429 | 8.76 万 |
| 307 | 6.66 万 |
| 301 | 3300 |

404 请求约占全部请求的 52%。
正常用户浏览网站时,不可能在两个多小时内制造近百万次 404。因此,这已经基本排除了正常流量增长的可能性。
当时首先想到的是:
- 随机 URL 枚举
- 漏洞路径扫描
- PHP 文件探测
- WordPress、DedeCMS 或其他系统历史文件扫描
- WebShell、后门文件存在性探测
但只看 404 还不能确定具体扫描内容,因此还需要继续查看资源类型、URL、Referer 和客户端信息。
四、99% 的异常请求来自同一个客户端 IP
EdgeOne 的客户端 IP 统计显示:
111.229.26.156:约 176.2 万次请求
而整个时间段的总请求量只有 177.68 万次。
也就是说,大约 99% 的异常请求都来自同一个客户端 IP。
地域统计则显示,绝大多数请求被识别为中国大陆上海来源。
这说明它并不是大量不同地区用户形成的正常访问,也不像典型的分布式攻击,而更接近:
一台服务器或者一个固定出口,持续执行高频自动化扫描。
需要注意的是,IP 地理位置只代表地址库中的归属信息,不能据此判断具体是谁发起了请求。
五、175 万次请求被识别为 .php
资源类型统计是这次事件中最关键的证据之一:
.php:175.54 万次- 无资源类型:7782 次
.js:4195 次.css:2475 次.asp:1384 次

接近 99% 的请求都指向 PHP 文件。
正常浏览器访问 WordPress 页面时,通常还会加载:
- HTML 页面
- CSS
- JavaScript
- 图片
- 字体
- JSON 接口
但此次请求几乎只有 PHP 文件,已经可以确定这不是正常浏览行为。
同时,Referer 统计显示:
约 176.95 万次请求没有 Referer。
浏览器、操作系统也几乎全部显示为 Other。
这些特征组合起来非常明显:
脚本直接构造不同的 PHP URL,并向网站发起请求,没有正常页面来源,也没有正常浏览器访问链路。
六、EdgeOne 缓存几乎没有挡住这些请求
缓存状态统计如下:
| 缓存状态 | 请求数 |
|---|---|
| MISS | 102.49 万 |
| other | 62.62 万 |
| dynamic | 11.74 万 |
| HIT | 8402 |

缓存命中只有 8402 次,占比不到 0.5%。
原因也不难理解。
如果攻击程序不断请求同一个地址,例如:
/test.php
/test.php
/test.php
CDN 还有可能缓存部分响应。
但如果它不断变化路径:
/a.php
/b.php
/c.php
/d.php
每一个 URL 都是新的 Cache Key,就会持续产生缓存 MISS。
因此,即使网站已经接入 EdgeOne,随机路径扫描仍然可能大量回源。
七、109 万次请求实际到达源站
为了确认这些异常请求有没有真正到达 ECS,我在 EdgeOne 中增加了:
L7 回源请求数
统计结果为:
109.43 万次回源请求。

总请求为 177.68 万次,意味着大约 61.6% 的请求发生了回源。
这说明本次异常流量并没有完全被 EdgeOne 边缘节点消化。
被 Web 防护识别并缓解的请求大约有 67 万次,而剩余约 110 万次请求中,绝大多数继续访问了源站。
此时最重要的问题变成了:
这些回源请求具体访问了哪些文件?有没有命中真实存在的异常 PHP 文件?
八、EdgeOne 安全分析已经无法查看完整历史
继续排查时,我发现 EdgeOne 的 Web 安全分析页面已经无法选择 7 月 30 日 15:00~18:30。
同时,这个站点此前也没有开通离线日志功能。
因此无法再通过 EdgeOne 获取这次事件的完整请求明细。
好在这些请求已经发生了回源,只要 Nginx 日志还在,就可以从源站日志中继续取证。
服务器使用 OneinStack,Nginx 日志位于:
/data/wwwlogs/
通过文件列表发现:
/data/wwwlogs/www.shuijingwanwq.com_nginx.log-20260731.gz
这个文件的压缩大小为 12 MB,解压后达到约 151 MB。
而前几天的正常日志压缩后通常只有 1.8~2.6 MB,日志体积的突然增加与这次异常流量完全吻合。
统计总行数:
log="/data/wwwlogs/www.shuijingwanwq.com_nginx.log-20260731.gz"
ls -lh "$log"
gzip -l "$log"
zcat "$log" | wc -l
结果为:
1,146,525 行。
EdgeOne 显示异常时段回源 1,094,300 次,而整个轮转日志有 1,146,525 行。扣除当天其他时间的正常请求后,二者已经非常接近。
九、Nginx 日志与 EdgeOne 回源数据几乎完全吻合
我进一步统计了 7 月 30 日 15:45~18:25 每分钟的 Nginx 请求数。
正常阶段每分钟只有几十次请求:
15:45 32
15:46 43
15:47 70
15:50 24
15:55 43
15:57 61
从 15:58 开始上涨:
15:58 663
15:59 777
16:00 7621
随后长时间保持在每分钟几千到一万多次。
最高的一分钟出现在 17:14:
15,961 次请求,约等于平均每秒 266 次。
到了 18:24,请求突然恢复正常:
18:23 11212
18:24 26
18:25 23
统计 15:58~18:23 的总请求数为:
1,093,547 次。
EdgeOne 的回源请求数为:
1,094,300 次。
两者只相差 753 次,误差约为 0.07%。
因此可以确认:
EdgeOne 统计的约 109 万次回源请求,就是 Nginx 日志中的这批请求。
十、日志样本确认是 PHP 和 WebShell 文件扫描
查看 16:00 的日志样本后,扫描内容变得非常清楚:
GET /watecmark.class.php
GET /19.php
GET /ftp.php
GET /dapeng.php
GET /bloods.php
GET /qrcode.png.php
GET /phpqrcode.php
GET /vhomeVF.php
GET /album.php
GET /HomeeeController.php
GET /funString.php
GET /dede-optimize-tables.php
GET /nobody.php
GET /1.asp
GET /inc_archives_funtions.php
GET /admin2021.php
GET /fancy_nav_left.php
GET /cssa.php
GET /basdir.php
GET /ticket.php
GET /en-us.php
GET /seo.php
绝大多数请求都具有以下特征:
Referer: "-"
User-Agent: "-"
这些文件并不只属于 WordPress。
例如:
/dede-optimize-tables.php
/1.asp
说明扫描器并没有先判断网站使用哪一种程序,而是使用一个非常大的文件名字典,批量尝试:
- PHP 后门文件
- WebShell 常见文件名
- CMS 历史文件
- 管理脚本
- 插件目录文件
- 伪装成图片或字体的 PHP 文件
- ASP 文件
因此,更准确的定性是:
一次大规模、路径高度离散的 PHP、ASP 和 WebShell 文件存在性扫描,同时形成了明显的 L7 Flood 效果。
十一、超过 108 万次 PHP 请求,但只有 30 次返回 200
为了确认扫描有没有命中真实存在的异常 PHP 文件,我统计了异常期间所有包含 .php 的请求。
结果如下:
| 状态码 | PHP 请求数 |
|---|---|
| 404 | 925,019 |
| 429 | 87,280 |
| 307 | 66,418 |
| 499 | 3408 |
| 503 | 1545 |
| 500 | 34 |
| 200 | 30 |
| 301 | 3 |
| 302 | 2 |
PHP 请求总数为:
1,083,739 次。
也就是说,异常期间约 99% 的源站请求都在探测 PHP 文件。
其中只有 30 次返回 200,相关路径包括:
/xmlrpc.php
/wp-cron.php
/wp-content/index.php
/wp-content/plugins/index.php
/wp-content/themes/index.php
/wp-includes/version.php
/wp-includes/post.php
/wp-includes/plugin.php
/wp-includes/load.php
/wp-includes/PHPMailer/SMTP.php
/wp-includes/Requests/src/Requests.php
这些都是 WordPress 本身存在的标准文件或入口,没有看到类似下面这样的可疑文件返回 200:
/shell.php
/ftp.php
/admin2021.php
/dapeng.php
因此,当前日志中没有发现扫描器成功命中明显 WebShell 的直接证据。
当然,这不能证明服务器绝对不存在安全问题,只能说明:
在本次扫描产生的日志里,没有看到明显异常 PHP 路径成功返回 200。
十二、429 来自服务器原有的 Nginx 限流
异常期间还有 87,280 个 PHP 请求返回 429。
进一步查看路径后发现,每一个 429 路径几乎都只请求了一次,例如:
/wp-content/plugins/plus.php
/wp-content/plugins/ftp.php
/wp-content/plugins/phpqrcode.php
/wp-content/plugins/dede-optimize-tables.php
/wp-content/plugins/basdir.php
/wp-content/plugins/album.php
这说明它不是某个固定接口被反复访问,而是扫描器仍然在不断更换 PHP 文件路径。
检查 Nginx 配置后,发现服务器原本配置了:
limit_req_zone $binary_remote_addr zone=site_limit:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
www.shuijingwanwq.com 的虚拟主机中还启用了:
limit_req zone=site_limit burst=50 nodelay;
limit_conn conn_limit 50;
limit_req_status 429;
因此,87,280 个 429 基本可以解释为:
请求到达源站以后,触发 Nginx
limit_req,由 Nginx 返回 429。
同时,异常期间还出现了 1545 个 503。
由于配置中启用了:
limit_conn conn_limit 50;
却没有单独设置 limit_conn_status,因此这些 503 很可能有一部分来自连接数限制。
十三、真正的问题:Nginx 限制的是 CDN 节点 IP
继续检查后发现,Nginx 已经编译了 Real IP 模块:
--with-http_realip_module
但配置文件中没有:
real_ip_header
set_real_ip_from
real_ip_recursive
也就是说,Nginx 没有把 EdgeOne 或 Cloudflare 传来的真实客户端 IP 恢复成 $remote_addr。
源站 access log 中记录的第一列也是:
122.246.2.238
122.246.2.213
43.175.104.101
43.175.104.231
而不是 EdgeOne 识别到的真实异常客户端 IP:
111.229.26.156
因此,当前限流配置中的:
$binary_remote_addr
实际代表的是:
EdgeOne 或 Cloudflare 的回源节点 IP。
并不是最终访问者 IP。
这会产生一个结构性问题。
假设大量正常用户和攻击请求经过同一个 CDN 回源节点,Nginx 会把它们全部视为同一个客户端,共享:
30 次请求/秒
burst 50
最多 50 个并发连接
攻击流量一旦占满这个额度,同一 CDN 回源节点上的正常请求也可能被一起返回 429 或 503。
所以这层限流虽然确实拦截了一部分扫描请求,但限流维度已经不准确,也存在误伤正常访问的可能。
十四、暂时不继续配置 EdgeOne 和 Cloudflare Real IP
理论上,可以分别为 EdgeOne 和 Cloudflare配置可信回源网段,并恢复:
- EdgeOne 的真实客户端 IP
- Cloudflare 的真实客户端 IP
- Nginx
$remote_addr - 基于真实 IP 的
limit_req - 基于真实 IP 的
limit_conn
但这意味着需要继续维护:
- EdgeOne 回源 IP 网段
- Cloudflare IP 网段
- 不同 CDN 的客户端 IP 请求头
- 源站公网直连防护
- 可信代理边界
- IP 网段后续更新
对于当前网站来说,这套方案会明显增加维护复杂度。
因此,我最终选择了一个更简单的处理方式:
由 EdgeOne 和 Cloudflare 在边缘侧负责真实客户端 IP 的安全防护;源站暂时取消这层已经无法准确区分真实客户端的 Nginx 限流。
这不是最完整的长期方案,但可以先消除当前已经确定存在的误限流问题。
十五、注释源站限流配置
首先备份虚拟主机配置:
conf="/usr/local/nginx/conf/vhost/www.shuijingwanwq.com.conf"
bak="${conf}.bak-disable-origin-limit-$(date +%Y%m%d-%H%M%S)"
cp -a "$conf" "$bak"
然后注释下面三行:
# limit_req zone=site_limit burst=50 nodelay;
# limit_conn conn_limit 50;
# limit_req_status 429;
实际使用的处理命令为:
sed -i \
-e 's/^[[:space:]]*limit_req zone=site_limit burst=50 nodelay;/ # limit_req zone=site_limit burst=50 nodelay;/' \
-e 's/^[[:space:]]*limit_conn conn_limit 50;/ # limit_conn conn_limit 50;/' \
-e 's/^[[:space:]]*limit_req_status 429;/ # limit_req_status 429;/' \
"$conf"
/usr/local/nginx/sbin/nginx -t
配置测试结果:
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
随后重新加载 Nginx:
/usr/local/nginx/sbin/nginx -s reload
nginx.conf 中的 zone 定义暂时保留:
limit_req_zone $binary_remote_addr zone=site_limit:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
仅定义 zone 并不会自动执行限流。只要虚拟主机中不再调用 limit_req 和 limit_conn,这些定义暂时不会影响请求。
这样既减少了修改范围,也方便以后需要时重新设计。
十六、验证中文站和英文站
重新加载 Nginx 后,分别测试中文站和英文站。
中文站由 EdgeOne 加速:
HTTP/2 200
server: nginx
eo-cache-status: MISS
出现 eo-cache-status 说明请求仍然经过 EdgeOne,只是本次没有命中缓存并发生了回源。
英文站由 Cloudflare 加速:
HTTP/2 200
server: cloudflare
age: 3379
cf-cache-status: HIT
英文站直接命中 Cloudflare 缓存。
两个站点均正常返回 200,说明注释源站限流后,EdgeOne、Cloudflare 和 Nginx 均正常工作。
十七、本次事件的最终结论
这次异常可以总结为:
2026 年 7 月 30 日约 15:58~18:23,
www.shuijingwanwq.com遭遇了一轮大规模 PHP 和 WebShell 文件路径扫描。
关键数据如下:
- EdgeOne L7 请求:177.68 万次
- L7 回源请求:109.43 万次
- Nginx 异常时段请求:109.35 万次
- PHP 请求:108.37 万次
- PHP 404:92.50 万次
- PHP 429:8.73 万次
- PHP 307:6.64 万次
- PHP 200:30 次
- 主要异常客户端 IP:
111.229.26.156 - 请求主要特征:无 Referer、无正常 User-Agent、大量不同 PHP 文件名
当前日志中没有看到明显异常 PHP 文件成功返回 200,因此暂时没有发现本次扫描成功命中 WebShell 的直接证据。
与此同时,这次调查还暴露出一个服务器配置问题:
网站接入 EdgeOne 和 Cloudflare 后,Nginx 原有的
$binary_remote_addr限流实际上按 CDN 回源节点 IP 计数,而不是按真实客户端 IP 计数。
最终采用的简化处理是:
暂时注释虚拟主机中的
limit_req、limit_conn和limit_req_status,避免对 EdgeOne、Cloudflare 回源节点限流;客户端级安全防护暂时交给 CDN 边缘节点处理。
十八、后续准备补充的措施
这次没有继续配置 EdgeOne 和 Cloudflare 的 Real IP,并不意味着这个问题以后完全不需要处理。
后续可以根据实际需要逐步完成:
- 开通 EdgeOne 离线日志,避免以后超过安全分析时间窗口后无法查看请求明细。
- 检查 EdgeOne 和 Cloudflare 的边缘防护、频率限制和 Bot 规则。
- 评估是否需要限制源站只能由 CDN 回源 IP 访问。
- 在可信代理边界明确以后,再恢复真实客户端 IP。
- 重新设计基于真实客户端 IP 的 Nginx 限流。
- 检查服务器中现有基于
$remote_addr的deny规则是否仍然有效。
不过这些都可以作为独立任务处理,没有必要在一次异常请求排查中全部完成。
这次最重要的成果,是确认了异常流量的真实类型、回源规模以及源站限流配置存在的问题,并先完成了一个简单、可回滚、不会继续扩大复杂度的修正。
Linux 服务器运维、部署与线上故障排查
如果你的网站或后端服务部署在 Linux 服务器上,遇到访问异常、Nginx 配置问题、MySQL / Redis 异常、Docker 服务不可用、磁盘占满、CPU / 内存过高等问题,可以联系我做一次远程排查。
适合以下场景:
✅ 网站打不开或访问不稳定
✅ Nginx / PHP-FPM 配置异常
✅ MySQL / Redis 性能或连接问题
✅ Docker 服务部署与维护
✅ 服务器迁移与环境配置
✅ CPU / 内存 / 磁盘异常排查
服务内容:
✅ Linux 环境检查
✅ 网站部署与迁移
✅ Nginx / PHP-FPM / MySQL / Redis 排查
✅ Docker 配置与维护
✅ 服务器性能分析
✅ 长期远程运维支持
如需咨询,请联系我,并注明:Linux 运维咨询。
联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com


发表回复