On July 31, 2026, while reviewing EdgeOne’s statistics from the previous day, I noticed a highly abnormal request curve in www.shuijingwanwq.com.
Under normal conditions, the website’s daily request volume remains relatively stable. However, on the afternoon of July 30, the number of L7 requests suddenly spiked and continued for over two hours.
Initially, I just wanted to verify whether this was ordinary crawler traffic. Later, by investigating layer by layer through EdgeOne metrics, cache status, origin pull request counts, and Nginx logs, I ultimately confirmed:
This was an automated scan targeting a large number of PHP file paths. During the anomaly, approximately 1.09 million requests actually reached the origin server, of which about 1.08 million targeted PHP paths.
During the investigation, I also discovered that after connecting to EdgeOne and Cloudflare, the server’s original Nginx rate limiting configuration could no longer work based on the real client IP, and instead might rate limit the CDN’s origin pull nodes.
This article documents the complete analysis process and the simplified handling solution adopted at the end.
1. Sudden Spike in EdgeOne Requests
From the EdgeOne metrics analysis page, a clear anomaly can be seen on July 30, 2026:
- Total L7 requests: 1,884,100
- L7 protection hits: 638,700
- Web protection mitigated requests: 676,300
- Unmitigated requests: 1,207,900
- L7 traffic: 4.76 GB
- Peak bandwidth: 4.33 Mbps
Compared to the previous comparison period:
- Requests increased by about 1180%
- Protection hits increased by over 52000%
- However, total traffic only increased by about 65%

The most notable point here is:
The number of requests increased more than tenfold, but the transferred traffic did not increase proportionally.
This usually means the response content of the new requests is very small, resembling a large volume of repeated requests, path scanning, malicious bots, or an HTTP Flood, rather than normal users集中 browsing articles and images.
2. Narrowing the Anomaly Window to 15:00–18:30
To avoid interference from other normal requests that day, I adjusted the statistics time window to:
July 30, 2026, 15:00–18:30
Within this time range, EdgeOne showed:
- L7 requests: 1,776,800
- Web protection mitigated: 676,300
- Unmitigated: 1,100,600
- L7 traffic: 2.72 GB
Looking at the curve, the anomalous traffic started rising around 15:50 and ended around 18:20.
Later, combining this with Nginx logs further confirmed that the actual anomaly window was:
Started around 15:58, fully erupted at 16:00, and ended at 18:23.
At 18:23, there were still over 11,000 requests per minute, but by 18:24, it dropped directly to 26 requests per minute.
This pattern of starting suddenly, running continuously, and then stopping abruptly also strongly matches an automated scanning task.
3. Nearly Half of the Requests Returned 404
Status code statistics show:
| Status Code | Requests |
|---|---|
| 404 | 928,500 |
| 200 | 687,000 |
| 429 | 87,600 |
| 307 | 66,600 |
| 301 | 3300 |

404 requests accounted for about 52% of all requests.
When normal users browse a website, they cannot generate nearly a million 404s in over two hours. Therefore, the possibility of normal traffic growth is essentially ruled out.
The first things that came to mind were:
- Random URL enumeration
- Vulnerability path scanning
- PHP file probing
- WordPress, DedeCMS, or other systems’ historical file scanning
- WebShell and backdoor file existence probing
However, looking only at 404s is not enough to determine the specific scan content, so I needed to continue checking resource types, URLs, Referers, and client information.
4. 99% of Abnormal Requests Came from the Same Client IP
EdgeOne’s client IP statistics show:
111.229.26.156: approximately 1,762,000 requests
Yet the total request volume for the entire period was only 1,776,800.
This means about 99% of the abnormal requests came from the same client IP.
Geographical statistics showed that the vast majority of requests were identified as originating from Shanghai, mainland China.
This indicates it was not normal access formed by a large number of users from different regions, nor did it look like a typical distributed attack. It was more akin to:
A single server or a fixed exit continuously performing high-frequency automated scanning.
It should be noted that IP geolocation only represents attribution information in the address database, and cannot be used to determine exactly who initiated the requests.
5. 1.75 Million Requests Identified as .php
Resource type statistics are one of the most crucial pieces of evidence in this incident:
.php: 1,755,400- No resource type: 7782
.js: 4195.css: 2475.asp: 1384

Nearly 99% of the requests pointed to PHP files.
When a normal browser accesses a WordPress page, it usually also loads:
- HTML pages
- CSS
- JavaScript
- Images
- Fonts
- JSON APIs
But this time, the requests were almost exclusively for PHP files, confirming that this was not normal browsing behavior.
Meanwhile, Referer statistics showed:
Approximately 1,769,500 requests had no Referer.
The browser and operating system also almost entirely showed as Other.
Combined, these characteristics are very clear:
A script directly constructed different PHP URLs and sent requests to the website, with no normal page source and no normal browser access path.
6. EdgeOne Cache Barely Blocked These Requests
Cache status statistics are as follows:
| Cache Status | Requests |
|---|---|
| MISS | 1,024,900 |
| other | 626,200 |
| dynamic | 117,400 |
| HIT | 8402 |

There were only 8402 cache hits, accounting for less than 0.5%.
The reason is not hard to understand.
If the attack program continuously requests the same address, for example:
/test.php
/test.php
/test.php
The CDN might still cache some responses.
But if it constantly changes paths:
/a.php
/b.php
/c.php
/d.php
Every URL is a new Cache Key, which will continuously generate cache MISSes.
Therefore, even if the website is already connected to EdgeOne, random path scanning can still generate a large number of origin pulls.
7. 1.09 Million Requests Actually Reached the Origin Server
To confirm whether these abnormal requests actually reached the ECS, I added the following metric in EdgeOne:
L7 origin pull request count
The statistical result was:
1,094,300 origin pull requests.

The total number of requests was 1,776,800, meaning about 61.6% of the requests resulted in an origin pull.
This shows that this anomalous traffic was not entirely absorbed by EdgeOne’s edge nodes.
About 670,000 requests were identified and mitigated by Web protection, while the remaining 1.1 million requests mostly continued to access the origin server.
At this point, the most important question became:
Which files did these origin pull requests specifically access? Did any of them hit actually existing abnormal PHP files?
8. EdgeOne Security Analysis Can No Longer View Complete History
While continuing the investigation, I found that EdgeOne’s Web security analysis page could no longer select the period from 15:00 to 18:30 on July 30.
At the same time, this site had not previously enabled the offline log feature.
Therefore, it was no longer possible to obtain the complete request details for this incident through EdgeOne.
Fortunately, these requests had already been pulled to the origin. As long as the Nginx logs were still there, I could continue gathering evidence from the origin server logs.
The server uses OneinStack, and the Nginx logs are located at:
/data/wwwlogs/
Through the file list, I found:
/data/wwwlogs/www.shuijingwanwq.com_nginx.log-20260731.gz
The compressed size of this file was 12 MB, and after decompression, it reached about 151 MB.
In contrast, normal logs from the previous few days were usually only 1.8 to 2.6 MB after compression. The sudden increase in log size perfectly matched this anomalous traffic.
Counting the total number of lines:
log="/data/wwwlogs/www.shuijingwanwq.com_nginx.log-20260731.gz"
ls -lh "$log"
gzip -l "$log"
zcat "$log" | wc -l
The result was:
1,146,525 lines.
EdgeOne showed 1,094,300 origin pulls during the anomaly window, while the entire rotated log had 1,146,525 lines. After deducting normal requests from other times of the day, the two figures were very close.
9. Nginx Logs and EdgeOne Origin Pull Data Almost Completely Match
I further calculated the Nginx request count per minute from 15:45 to 18:25 on July 30.
During the normal phase, there were only dozens of requests per minute:
15:45 32
15:46 43
15:47 70
15:50 24
15:55 43
15:57 61
It started rising from 15:58:
15:58 663
15:59 777
16:00 7621
Subsequently, it stayed at several thousand to over ten thousand requests per minute for a long time.
The highest minute occurred at 17:14:
15,961 requests, equivalent to an average of 266 requests per second.
By 18:24, requests suddenly returned to normal:
18:23 11212
18:24 26
18:25 23
The total number of requests from 15:58 to 18:23 was:
1,093,547.
EdgeOne’s origin pull request count was:
1,094,300.
The two figures differ by only 753, an error of about 0.07%.
Therefore, it can be confirmed:
The approximately 1.09 million origin pull requests counted by EdgeOne are this exact batch of requests in the Nginx logs.
10. Log Samples Confirm PHP and WebShell File Scanning
After viewing the log samples from 16:00, the scanning content became very clear:
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
The vast majority of requests had the following characteristics:
Referer: "-"
User-Agent: "-"
These files do not belong exclusively to WordPress.
For example:
/dede-optimize-tables.php
/1.asp
This shows that the scanner did not first determine which program the website uses, but instead used a very large filename dictionary to batch test:
- PHP backdoor files
- Common WebShell filenames
- CMS historical files
- Admin scripts
- Plugin directory files
- PHP files disguised as images or fonts
- ASP files
Therefore, a more accurate characterization is:
A large-scale, highly discrete path scan for PHP, ASP, and WebShell file existence, which simultaneously formed a clear L7 Flood effect.
11. Over 1.08 Million PHP Requests, but Only 30 Returned 200
To confirm whether the scan hit any actually existing abnormal PHP files, I counted all requests containing .php during the anomaly.
The results are as follows:
| Status Code | PHP Requests |
|---|---|
| 404 | 925,019 |
| 429 | 87,280 |
| 307 | 66,418 |
| 499 | 3408 |
| 503 | 1545 |
| 500 | 34 |
| 200 | 30 |
| 301 | 3 |
| 302 | 2 |
The total number of PHP requests was:
1,083,739.
This means that about 99% of the origin server requests during the anomaly were probing for PHP files.
Only 30 of these returned 200, and the related paths included:
/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
These are all standard files or entry points that exist in WordPress itself. I did not see any suspicious files like the following return 200:
/shell.php
/ftp.php
/admin2021.php
/dapeng.php
Therefore, no direct evidence was found in the current logs that the scanner successfully hit an obvious WebShell.
Of course, this does not prove that the server is absolutely free of security issues; it only shows that:
In the logs generated by this scan, no obviously abnormal PHP paths successfully returned 200.
12. The 429s Came from the Server’s Original Nginx Rate Limiting
During the anomaly, 87,280 PHP requests also returned 429.
After further checking the paths, I found that almost every 429 path was requested only once, for example:
/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
This indicates that it was not a fixed API being repeatedly accessed, but rather the scanner continuously changing PHP file paths.
After checking the Nginx configuration, I found that the server originally configured:
limit_req_zone $binary_remote_addr zone=site_limit:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
The virtual host for www.shuijingwanwq.com also enabled:
limit_req zone=site_limit burst=50 nodelay;
limit_conn conn_limit 50;
limit_req_status 429;
Therefore, the 87,280 429s can basically be explained as:
After the requests reached the origin server, they triggered Nginx
limit_req, and Nginx returned 429.
At the same time, 1545 503s occurred during the anomaly.
Because the configuration enabled:
limit_conn conn_limit 50;
without separately setting limit_conn_status, some of these 503s likely came from the connection limit.
13. The Real Problem: Nginx is Rate Limiting CDN Node IPs
Upon further inspection, I found that Nginx had already compiled the Real IP module:
--with-http_realip_module
But the configuration file did not contain:
real_ip_header
set_real_ip_from
real_ip_recursive
In other words, Nginx was not restoring the real client IP passed by EdgeOne or Cloudflare to $remote_addr.
The first column recorded in the origin server’s access log was also:
122.246.2.238
122.246.2.213
43.175.104.101
43.175.104.231
Rather than the real abnormal client IP identified by EdgeOne:
111.229.26.156
Therefore, the current rate limiting configuration’s:
$binary_remote_addr
actually represents:
The origin pull node IPs of EdgeOne or Cloudflare.
Not the final visitor IP.
This creates a structural problem.
Assuming a large number of normal users and attack requests pass through the same CDN origin pull node, Nginx will treat them all as the same client, sharing:
30 requests/second
burst 50
up to 50 concurrent connections
Once the attack traffic fills this quota, normal requests on the same CDN origin pull node might also be returned 429 or 503 together.
So although this layer of rate limiting did block some scanning requests, the rate limiting dimension is no longer accurate, and there is a possibility of collateral damage to normal access.
14. Temporarily Not Continuing to Configure EdgeOne and Cloudflare Real IP
Theoretically, trusted origin pull network segments could be configured separately for EdgeOne and Cloudflare, and restore:
- EdgeOne’s real client IP
- Cloudflare’s real client IP
- Nginx
$remote_addr limit_reqbased on real IPlimit_connbased on real IP
But this means I would need to continue maintaining:
- EdgeOne origin pull IP segments
- Cloudflare IP segments
- Client IP request headers for different CDNs
- Origin server public direct connection protection
- Trusted proxy boundaries
- Future updates to IP segments
For the current website, this solution would significantly increase maintenance complexity.
Therefore, I ultimately chose a simpler approach:
Let EdgeOne and Cloudflare handle security protection for real client IPs at the edge; the origin server temporarily removes this layer of Nginx rate limiting that can no longer accurately distinguish real clients.
This is not the most complete long-term solution, but it can first eliminate the currently confirmed issue of incorrect rate limiting.
15. Commenting Out the Origin Server Rate Limiting Configuration
First, back up the virtual host configuration:
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"
Then comment out the following three lines:
# limit_req zone=site_limit burst=50 nodelay;
# limit_conn conn_limit 50;
# limit_req_status 429;
The actual processing command used was:
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
Configuration test result:
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
Then reload Nginx:
/usr/local/nginx/sbin/nginx -s reload
The zone definition in nginx.conf is temporarily retained:
limit_req_zone $binary_remote_addr zone=site_limit:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
Just defining a zone does not automatically enforce rate limiting. As long as the virtual host no longer calls limit_req and limit_conn, these definitions will temporarily not affect requests.
This reduces the scope of modifications and makes it convenient to redesign later if needed.
16. Verifying the Chinese and English Sites
After reloading Nginx, I tested the Chinese and English sites separately.
The Chinese site is accelerated by EdgeOne:
HTTP/2 200
server: nginx
eo-cache-status: MISS
The appearance of eo-cache-status indicates that the request still went through EdgeOne, but this time it missed the cache and resulted in an origin pull.
The English site is accelerated by Cloudflare:
HTTP/2 200
server: cloudflare
age: 3379
cf-cache-status: HIT
The English site directly hit the Cloudflare cache.
Both sites returned 200 normally, indicating that after commenting out the origin server rate limiting, EdgeOne, Cloudflare, and Nginx are all working properly.
17. Final Conclusion of This Incident
This anomaly can be summarized as:
From about 15:58 to 18:23 on July 30, 2026,
www.shuijingwanwq.comexperienced a large-scale PHP and WebShell file path scan.
The key data is as follows:
- EdgeOne L7 requests: 1,776,800
- L7 origin pull requests: 1,094,300
- Nginx requests during the anomaly: 1,093,500
- PHP requests: 1,083,700
- PHP 404s: 925,000
- PHP 429s: 87,300
- PHP 307s: 66,400
- PHP 200s: 30
- Main abnormal client IP:
111.229.26.156 - Main request characteristics: no Referer, no normal User-Agent, large number of different PHP filenames
No obviously abnormal PHP files successfully returned 200 in the current logs, so no direct evidence has been found that this scan successfully hit a WebShell.
At the same time, this investigation also exposed a server configuration issue:
After the website connected to EdgeOne and Cloudflare, Nginx’s original
$binary_remote_addrrate limiting actually counted by CDN origin pull node IP, rather than by real client IP.
The simplified handling ultimately adopted was:
Temporarily comment out
limit_req,limit_conn, andlimit_req_statusin the virtual host to avoid rate limiting EdgeOne and Cloudflare origin pull nodes; client-level security protection is temporarily left to the CDN edge nodes.
18. Follow-up Measures to Be Supplemented
The fact that I did not continue configuring Real IP for EdgeOne and Cloudflare this time does not mean this issue never needs to be addressed in the future.
Subsequent steps can be gradually completed based on actual needs:
- Enable EdgeOne offline logs to avoid being unable to view request details after exceeding the security analysis time window in the future.
- Check edge protection, rate limiting, and Bot rules for EdgeOne and Cloudflare.
- Evaluate whether access to the origin server needs to be restricted to CDN origin pull IPs only.
- Restore the real client IP after the trusted proxy boundary is clearly defined.
- Redesign Nginx rate limiting based on the real client IP.
- Check whether the existing
denyrules based on$remote_addron the server are still valid.
However, these can all be handled as independent tasks; there is no need to complete them all at once during an abnormal request investigation.
The most important outcome this time was confirming the true nature of the anomalous traffic, the scale of origin pulls, and the existing issues with the origin server’s rate limiting configuration, and first completing a simple, reversible fix that does not continue to increase complexity.

