Back to blog

How to Protect Your WordPress Site From Unwanted Bot Traffic With Cloudflare

Stop scrapers, credential-stuffing bots, and xmlrpc abuse before they hit your server. A step-by-step guide to blocking WordPress bot traffic with Cloudflare.

magicwp/blog

Every WordPress site attracts bots. Some are welcome, like search engine crawlers and uptime monitors. Most are not: content scrapers, credential-stuffing scripts hammering wp-login.php, and clients probing xmlrpc.php for a way in. Left alone, this traffic burns server resources, pollutes your analytics, and occasionally turns into a real security problem. Putting Cloudflare in front of your site lets you filter a large share of that noise at the network edge, before it ever reaches PHP or your database.

This guide walks through protecting your WordPress site from unwanted bot traffic using Cloudflare, mostly with tools available on the free plan. You'll turn on Cloudflare's built-in bot detection, add targeted challenges for the endpoints attackers actually go after, rate-limit login attempts, and verify the changes are working without breaking legitimate crawlers or your own site's background requests.

TL;DR

  • Proxy your site through Cloudflare (orange cloud on), then enable Bot Fight Mode (free) under Security → Settings → Bot traffic for baseline coverage.
  • Add WAF custom rules that apply a Managed Challenge to /wp-login.php, /wp-admin, and /xmlrpc.php, while excluding verified bots and the admin-ajax.php endpoint so you don't break the front end.
  • Add a rate limiting rule on POST to /wp-login.php to blunt brute-force attempts.
  • Bot Fight Mode is aggressive and can't be skipped with WAF rules; on paid plans, Super Bot Fight Mode gives per-category control and a WordPress loopback option. Verify results in Security → Analytics and Security → Events.

Prerequisites

Before you start, make sure you have the following in place:

  • A WordPress site you administer. You need access to wp-admin and, ideally, to your host's dashboard. If you host with MagicWP, you can reach wp-admin instantly through Magic Login without hunting for credentials.
  • A Cloudflare account with your domain added. Your domain's DNS must be managed by Cloudflare and the site records must be proxied (the orange cloud icon, not grey). Only proxied traffic passes through Cloudflare's security layer. Cloudflare's free plan is enough for everything in the core steps here.
  • Your site's real origin details. Know your origin server's IP and any monitoring or integration IPs you run, so you can allow them explicitly and avoid locking yourself out.
  • A current backup. You're changing how traffic reaches your site, and an over-broad rule can block real visitors. Take a fresh backup first. On MagicWP you can create an on-demand backup before you begin, with one-click restore if anything goes wrong.
  • A way to test from outside your network, such as a phone on mobile data or an incognito window, so you can confirm rules behave as expected for anonymous visitors.

A quick note on caching plugins and page rules: bot mitigation happens at Cloudflare's edge, independent of any caching plugin on the origin. The two don't conflict, but if you use a plugin that manages Cloudflare settings via API, make manual dashboard changes in a way that plugin won't overwrite.

Step 1 - Confirm your site is proxied through Cloudflare

Cloudflare can only challenge or block traffic it actually sees. If your DNS records point at your origin with the grey cloud (DNS-only), requests bypass Cloudflare's security features entirely.

In the Cloudflare dashboard, select your domain and open DNS → Records. Check the A (or AAAA) record for your root domain and the www record. The proxy status should read Proxied with an orange cloud. If it shows a grey cloud, click it to enable the proxy.

Important: Only proxy records for web traffic (your site's A/AAAA and www). Leave records for mail (MX), and any service that shouldn't route through Cloudflare, as DNS-only. Proxying a mail record, for example, will break email delivery.

Give DNS a few minutes to settle, then load your site over HTTPS and confirm it still works normally. You can verify the request is passing through Cloudflare by checking the response headers for a cf-ray header, which Cloudflare adds to proxied responses.

Step 2 - Enable Bot Fight Mode

Bot Fight Mode is a free product that helps detect and mitigate bot traffic on your domain. It's the fastest baseline: a single toggle that issues challenges to requests Cloudflare classifies as automated and not on its verified-bot list.

To turn it on:

  1. In the Cloudflare dashboard, go to Security → Settings.
  2. Under Filter by, choose Bot traffic.
  3. Find Bot Fight Mode and toggle it On.

When enabled, it identifies traffic matching patterns of known bots and issues computationally expensive challenges in response, protecting entire domains without endpoint restrictions. Those challenges make automated abuse slow and costly while staying invisible to normal browsers.

Two things to understand before you rely on it:

  • Bot Fight Mode can't be tuned or skipped. It cannot be customized via WAF custom rules, and you cannot bypass or skip it using WAF custom rules or Page Rules, because it does not run on the Ruleset Engine. That means if it challenges a legitimate automated client you depend on (say, your own monitoring or a headless integration), your only options on the free plan are to turn it off or move up to Super Bot Fight Mode. Bot Fight Mode and Super Bot Fight Mode are aggressive by design.
  • It's a blunt instrument. It handles the obvious, low-effort automated traffic well. It won't give you per-endpoint control or let you treat your login page differently from your blog. That's what the next steps add.

If your site runs legitimate automation that Bot Fight Mode interferes with, note the affected paths now; you'll either exclude that traffic at the source or consider Super Bot Fight Mode in the optional step later.

Step 3 - Challenge the endpoints attackers target

WordPress is predictable, which is convenient for you and for attackers. A handful of paths receive the overwhelming share of malicious automation: the login form, the admin area, and the legacy XML-RPC endpoint. Instead of challenging your whole site (which adds friction for real readers), apply a Managed Challenge to just these paths.

A Managed Challenge lets Cloudflare decide how much friction to apply. Most humans pass it without interaction or with a single click, while automated clients get stopped. It's a good default because it rarely inconveniences real users.

Step 3.1 - Add a Managed Challenge for the login and admin area

  1. Go to Security → Security rules (on some accounts, Security → WAF → Custom rules).
  2. Click Create rule → Custom rules.
  3. Give the rule a clear name, such as Challenge wp-login and wp-admin.
  4. Choose Edit expression and enter an expression like the following, replacing the host with your own domain:
(http.host in {"example.com" "www.example.com"}
 and (http.request.uri.path eq "/wp-login.php"
      or starts_with(http.request.uri.path, "/wp-admin"))
 and not cf.client.bot
 and not http.request.uri.path contains "/wp-admin/admin-ajax.php")
  1. Under Then take action, select Managed Challenge.
  2. Click Deploy.

Two exclusions in that expression matter:

  • not cf.client.bot skips Cloudflare's verified bots, so you don't accidentally challenge legitimate crawlers and services that need to reach these paths.
  • not ... "/wp-admin/admin-ajax.php" excludes admin-ajax.php. Many themes and plugins call this endpoint from the front end for logged-out visitors (search, filters, add-to-cart on WooCommerce). Challenging it can break site functionality for real users, so leave it out.

After deploying, wait a minute, then open your login page from an incognito window or another network. You should briefly see a challenge screen before the login form loads. If it loads normally without a challenge, double-check that your host matches the expression exactly.

Step 3.2 - Handle xmlrpc.php

xmlrpc.php is a frequent target for brute-force amplification and pingback abuse. Most modern sites don't need it. But some plugins still rely on it (Jetpack is the common example, along with certain mobile app and remote-publishing workflows), so decide based on your setup:

  • If nothing on your site uses XML-RPC, block it outright. Create a custom rule:
(http.host in {"example.com" "www.example.com"}
 and http.request.uri.path eq "/xmlrpc.php")

Set the action to Block and deploy. This cuts the traffic off before it reaches PHP.

  • If a plugin needs XML-RPC, don't block it globally, or you'll break that plugin. Use Managed Challenge instead of Block, or scope the block with additional conditions (for example, only challenge requests that aren't from the verified services you rely on). Test the dependent plugin afterward.

Important: Before blocking xmlrpc.php, confirm nothing depends on it. An easy check is to disable the endpoint temporarily and exercise the plugins that might use it (publishing from a mobile app, Jetpack features). If everything still works, you're safe to block it.

Step 3.3 - Consider a REST API rule (optional)

The WordPress REST API at /wp-json/ can leak more than you intend, such as usernames via the users endpoint. Blocking it wholesale is risky because the block editor, many plugins, and WooCommerce all use the REST API. If you want to reduce exposure without breaking the site, challenge only the user-enumeration path rather than the whole API:

(http.host in {"example.com" "www.example.com"}
 and starts_with(http.request.uri.path, "/wp-json/wp/v2/users"))

Set the action to Managed Challenge. Test the editor and your plugins afterward, since REST behavior varies a lot between setups.

Step 4 - Rate-limit login attempts

Challenges slow bots down, but a determined brute-force script can still throw a high volume of login attempts. A rate limiting rule caps how often any single client can hit your login endpoint, which is one of the most effective and lowest-risk protections you can add.

A common, conservative starting point is a handful of login POSTs per few minutes per IP. Adjust to your traffic; a busy multi-author site needs more headroom than a single-author blog.

  1. Go to Security → WAF → Rate limiting rules (labeling varies slightly by account and plan).
  2. Create a new rule named something like Rate limit wp-login POST.
  3. Match requests to the login endpoint using the POST method, for example a path equal to /wp-login.php and request method POST.
  4. Set the threshold, for example 5 requests per 60 seconds per client IP.
  5. Choose an action. Managed Challenge or Block for the duration are both reasonable; challenging is more forgiving of shared-IP office networks.
  6. Deploy.

Rate limiting availability and the number of rules depend on your Cloudflare plan, and the exact limits change over time, so treat specific caps as plan-dependent and confirm what's available on your account in the dashboard. Matching only POST is deliberate: it targets actual login submissions, not people simply viewing the login page.

Step 5 - Allowlist the traffic you trust

Aggressive rules will eventually catch something you didn't mean to catch: your own monitoring, a payment processor's callbacks, a deployment webhook, or your office IP. Set up allowances before that becomes an outage.

  • Verified bots are already excluded in the Step 3 expressions via not cf.client.bot. Keep that exclusion in any rule where legitimate crawlers or services need access.
  • Your own IPs and services: if you run monitoring or integrations from known addresses, create a high-priority custom rule with the Skip action for those source IPs, or exclude them in your rule expressions. As placeholders, a documentation-range client might be <198.51.100.5> or <2001:db8:1::5>; use your real addresses.
  • WordPress background requests: WordPress makes loopback requests to itself for cron, the Site Health tool, and various plugins. Overly broad edge rules can interfere with these. If you see failures in Tools → Site Health after tightening rules, check whether a rule is catching your origin's own requests and add an exception.

Important: Order matters. In Cloudflare's WAF, custom rules evaluate in order, and a Skip rule earlier in the list lets trusted traffic bypass later challenge or block rules. Put your allow/skip rules above your challenge and block rules.

Step 6 - Verify it's working

Don't assume the rules do what you intended. Confirm it, and watch for false positives over the first day or two.

Security Events. Go to Security → Events (called Firewall Events on some accounts). Each entry shows the action taken, which rule triggered, the source IP, user agent, URI path, and country. Filter for your login, admin, and xmlrpc paths and confirm you're seeing bot traffic challenged or blocked, and that real visitors aren't caught. Look for signs of false positives: challenges hitting known monitoring or payment services, or a spike of challenged requests from countries where you have genuine users.

Bot Analytics / Analysis. In Security → Analytics (Bot Analysis, where available on your plan), you get a breakdown of human versus automated traffic. Cloudflare scores each request and groups it into categories such as automated and likely automated. Watching this over a few days tells you whether the automated share is dropping.

Functional testing. From outside your network, confirm: your site's front end loads with no challenge, the login page shows a challenge then works, and admin actions (including anything using admin-ajax.php) behave normally. If you host WooCommerce, test the cart and checkout specifically, since those flows lean on AJAX and the REST API.

If something legitimate is being blocked, don't disable everything. Find the specific rule in Security → Events, then either narrow its expression or add a Skip rule above it for the affected traffic.

Step 7 - Add Super Bot Fight Mode (Optional, paid plans)

If you're on a Cloudflare paid plan and need finer control than Bot Fight Mode offers, Super Bot Fight Mode is the upgrade. It is available on Pro, Business, and Enterprise plans and, unlike the free toggle, it runs on the Ruleset Engine, so you can create exceptions with WAF Skip rules.

Super Bot Fight Mode gives you separate toggles for definitely automated traffic, likely automated traffic, and verified bots, each with Allow, Block, or Managed Challenge, plus a JavaScript-served challenge option. A common configuration is to block traffic that's definitely automated, apply a Managed Challenge to likely-automated traffic, and allow verified bots.

To configure it: go to Security → Settings, filter by Bot traffic, open Super Bot Fight Mode, and set the action for each category. If you're upgrading from Bot Fight Mode, you must first disable Bot Fight Mode in your bot settings, since the two shouldn't run together.

One WordPress-specific option is worth enabling here. WordPress relies on making loopback requests to monitor and occasionally administer itself, and you can opt in to optimize Super Bot Fight Mode for WordPress; when enabled, automated loopback requests made by your WordPress site are authorized even when Super Bot Fight Mode blocks other bots. Turn it on under the Super Bot Fight Mode configuration (the Optimize for WordPress toggle) to avoid Cloudflare interfering with your site's own diagnostics.

Note: If you also use Cloudflare Tunnel, keep Definitely Automated set to Allow, or tunnels may fail with a websocket: bad handshake error.

Conclusion

You've moved unwanted bot traffic off your server and onto Cloudflare's edge, where it belongs. Bot Fight Mode gives you a free baseline, targeted Managed Challenges protect the login, admin, and XML-RPC endpoints attackers actually probe, a rate limit blunts brute-force attempts, and allowlisting keeps your own tools and verified crawlers working. Verifying in Security → Events and Bot Analytics turns "I think it's working" into "I can see it's working."

A few habits keep this effective over time. Cloudflare's dashboard labels and plan features change, so check the current dashboard rather than relying on a screenshot from last year, and treat any specific plan limit as something to confirm on your account. Revisit your Security Events periodically to catch new attack patterns and false positives. And remember that edge filtering complements, not replaces, good origin hygiene: strong passwords, two-factor authentication, and up-to-date core, themes, and plugins.

One more layer worth having is a host that isolates and backs up your site independently of Cloudflare. MagicWP runs each WordPress site in its own isolated container with a managed WAF, malware scanning, and daily off-site backups with one-click restore, so if a rule change or an attack does slip through, recovery is fast. If you'd rather spend your time tuning rules than managing infrastructure, that's the kind of foundation it sits on.

Next steps

MF
Mohammadhossein Fakhraei
MagicWP
Writing about WordPress, performance, and the infrastructure that makes sites fast.

Get the best of MagicWP in your inbox.

Monthly engineering notes, product updates, and WordPress performance tips. No spam, unsubscribe anytime.

Join 12,000+ builders. We send one email a month.