Guide
Stopping a wp-login brute force at the Cloudflare edge.
A site felt slow. The suggested fix was a bigger server. Before spending that money we looked at what the traffic was actually made of, and found a login page absorbing 46% of every request reaching the origin. This is how to check whether the attack is even your problem, and how to stop it in minutes if it is.
The symptom, and the expensive wrong answer
The site felt slow. That is the whole brief you usually get, and it is enough to send most people down the wrong road. The obvious next step, the one already on the table, was to pay for a bigger server. It is a plausible response to slowness and it is wrong more often than it is right, because it treats a symptom without checking the cause.
Before agreeing to that recurring cost, we looked at what the traffic reaching the server was actually made of. That is the step almost nobody takes, and it is the one that decides whether you are about to spend money on the right thing.
Measure first: what is the traffic made of
You cannot fix a load problem you have not characterised. The question is not "is the server busy", it is "busy doing what". Server log analysis answers it directly. Group the requests reaching the origin by path and see what dominates.
# the paths hitting the origin most, from an access log
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head
# how many of today's requests are hitting wp-login specifically
grep -c 'POST /wp-login.php' access.log On this site the answer was stark. /wp-login.php was absorbing about 46% of every request reaching the origin. That is a brute force attack, running at 21,626 hits a day, trying to guess a password one POST at a time. Almost half the server's work was answering an attacker.
The finding that changed the plan
Here is the part that mattered more than the attack itself. The server was sitting at 7.5% CPU. The attack was noisy, not heavy. It was generating a huge count of requests, but each one was cheap, and the machine was nowhere near its limit.
So the attack was real, and it was not what was making the site feel slow. Two separate facts, and conflating them is exactly how you end up buying a bigger server that fixes neither. If we had upgraded the server, the attack would have carried on, the site would have felt the same, and the client would be paying more every month for the privilege.
The rule this illustrates
A high request count and a high server load are different measurements. Check both before you act. An attack can be alarming in the logs and irrelevant to performance, and the reverse is also true: a small number of expensive requests can flatten a server while the request count looks calm.
Stopping it at the edge, not the origin
The right place to stop a brute force is before it reaches your server at all. A security plugin that blocks login attempts still runs WordPress, and the database, for every attempt it blocks. You are still paying to reject the traffic. Stopping it at the CDN edge means the attacker never touches the origin.
On Cloudflare the tool is a Managed Challenge on the login path. The critical detail, the one that makes this safe to ship, is the skip rule that allowlists the real admin so the fix does not lock out the person who needs to log in.
- A rule on the login path. Match requests to
/wp-login.phpand the/wp-adminentry, and apply a Managed Challenge. Legitimate humans pass it in a click. Automated password guessing does not. - A skip rule above it, allowlisting the admin IP. This is what stops the fix becoming a new problem. The person who administers the site never sees the challenge, because their IP is matched and skipped before the challenge rule is evaluated. Order matters: the skip has to sit above the challenge.
- Confirm the challenge is at the edge, not the origin. The whole point is that blocked attempts never reach WordPress. Check that the challenge is served by Cloudflare before the request is proxied, not by a plugin after it.
The mistake to avoid
Blocking the login path without an allowlist, then discovering you cannot get in either. Build the skip rule first, confirm your own IP is on it, and only then turn on the challenge. If your admin IP is dynamic, use a small range or an authenticated bypass rather than a single address.
The result, verified in the logs
Hostile traffic to the login path dropped to zero within fifteen minutes of the rule going live, verified in the logs rather than assumed, with legitimate admin access confirmed working. Fifteen minutes from diagnosis to a fix running in production.
Just as valuable, and easy to forget in the relief of stopping the attack: the client did not spend money upgrading a server that was running at 7.5% load. A misdiagnosis there would have cost real money every month and fixed nothing, because the load was never the problem and the attack was never a load problem.
A checklist for your own site
Run it in order. The measurement steps come before the fix on purpose.
- Group origin requests by path and find what dominates. If a login or xmlrpc path is near the top, you have this.
- Check the server's actual CPU and memory load. Decide whether the attack is a performance problem or just a security one. They are different.
- If the site is genuinely slow, keep looking after you stop the attack, because the slowness is probably somewhere else entirely.
- Build the Cloudflare skip rule allowlisting your admin IP first. Confirm you can still reach the login.
- Add the Managed Challenge on the login and admin paths, above nothing, below the skip.
- Confirm blocked attempts stop appearing in the origin logs. If they still appear, the block is happening after the origin, not before it.
- Consider disabling
xmlrpc.phpif nothing you run needs it, since it is the other common brute force and amplification vector. - Before anyone quotes a bigger server, produce the load numbers. A server upgrade should be justified by load, not by a request count.
What this adds up to
Two lessons, and the second is the expensive one. First, stop brute force traffic at the edge so it never costs your origin anything, with an allowlist so you do not lock yourself out. Second, and more importantly, measure what "slow" is actually made of before you spend money on it. A dramatic-looking attack and a slow site can be entirely unrelated, and the only way to know is to look at the load, not the log count.
The whole diagnosis took the time it takes to read an access log properly. The server upgrade it avoided would have been a monthly bill forever.
Stopping traffic before it reaches the origin is edge and infrastructure work, and it is the cheapest place to solve a load problem. Characterising the traffic in the first place is a tooling problem, and grouping requests by path is the kind of thing a small purpose-built script answers in minutes where a dashboard will not. Either way the order is the same: measure first, spend second.
Keep reading
If this is your problem
Book me
Is your login page under attack?
Send us an access log, or just the site. We will tell you what your traffic is actually made of, whether it is slowing you down, and whether a bigger server would be money wasted.