2026年11月12日

2026年11月12日

Advanced Cloudflare Settings for WordPress: WAF, Rate Limits, Caching

This article is a localized edition of the Japanese original. Read the Japanese original

Cloudflare is more than a CDN (content delivery): it also offers a WAF (a system that stops malicious requests), rate limiting, and programs that run at the edge (Workers). This article covers settings for a WordPress site served through Cloudflare: protecting the login screen, tuning the cache, and adding security headers. Plan limits and screen names were checked against the official Cloudflare documentation (developers.cloudflare.com) as of November 2026. Cloudflare's dashboard changes often, so if a name differs, check the official documentation.

If you have not set up Cloudflare yet, or need to pass visitors' real IP addresses to your server through Cloudflare, see "How to set up Cloudflare for WordPress" first.

Main limits by plan (as of November 2026)

Feature Free Pro Business
WAF custom rules 5 20 100
Regex in custom rules Not available Not available Available
Rate limiting rules 1 (counted per IP, 10-second period, 10-second block, conditions such as path) Expanded depending on plan Expanded depending on plan
Managed rules Cloudflare Free Managed Ruleset Cloudflare Managed Ruleset and OWASP Core Ruleset also available Same as Pro
Cache Rules 10 25 50
Page Rules (deprecated) 3 20 50
Workers Free up to 100,000 requests per day and 10 ms of CPU per invocation Paid Workers plan from USD 5 per month Same as Pro

Protect the login screen and more with WAF custom rules

Custom rules block requests that match a condition, or show them a challenge (a check for bots), before they reach your server.

  1. In the Cloudflare dashboard, select your domain and open the "Security rules" page.
  2. Choose "Create rule", then "Custom rules".
  3. Enter a name in "Rule name" and build the condition under "When incoming requests match". Besides picking from the form, you can write the expression directly with "Edit expression".
  4. Choose the action under "Then take action" and enable it with "Deploy".

Here are three examples commonly used with WordPress. The Free plan allows five, so add the ones you need first.

Example 1: Challenge access to wp-login.php from outside Japan

This example is for a site where people log in only from Japan. Requests from outside Japan get a "Managed Challenge" to check whether they are bots.

(http.request.uri.path eq "/wp-login.php" and ip.src.country ne "JP")
  • Action: Managed Challenge
  • Anyone who manages the site while traveling abroad or from an overseas server will also go through the challenge. If you want to stop logins from outside Japan altogether, choose "Block", but to avoid locking yourself out, start with "Managed Challenge" and watch how it behaves.
  • Use ip.src.country for the country (the older ip.geoip.country is deprecated).

Example 2: Block access to xmlrpc.php

(http.request.uri.path eq "/xmlrpc.php")
  • Action: Block
  • XML-RPC can be used for password brute-forcing and mass pingbacks. However, Jetpack, some smartphone apps and external publishing tools use XML-RPC, so confirm that you do not use it before blocking it. How to disable it on the WordPress side is covered in "How to disable XML-RPC in WordPress".

Example 3: Block PHP execution in the uploads folder

This prevents attacks in which a PHP file is placed in wp-content/uploads, the folder for images and other uploads, and then executed. A normal WordPress site never needs PHP files in this folder to be opened directly.

(http.request.uri.path contains "/wp-content/uploads/" and http.request.uri.path contains ".php")
  • Action: Block

After adding rules, check the security analytics screens (Analytics and Events under Security) to see how many requests each rule acted on, and make sure legitimate traffic is not being blocked.

Limit login attempts with rate limiting

Rate limiting rules stop large numbers of requests from the same IP address in a short time. Create one from "Create rule" on the same "Security rules" page as custom rules by choosing "Rate limiting rules".

On the Free plan you can create only one; only some fields, such as the path, can be used in the condition, and both the counting period and the block duration are 10 seconds. Using the request method as a condition (counting only POST requests, for example) is a feature of higher plans. A Free-plan example looks like this.

Setting Value
Condition URI Path equals /wp-login.php
Counting characteristic IP
Threshold 5 requests per 10 seconds (GET requests are counted too, so choose a number a normal login will not exceed)
Action Block (for 10 seconds)

A setup that combines rate limiting with custom rules is also covered in "How to limit WordPress login attempts with Cloudflare".

Check the managed rules

The Free plan includes the "Cloudflare Free Managed Ruleset", a set of rules that blocks attacks on widely exploited vulnerabilities and is updated by Cloudflare. Pro and higher plans can also use the larger "Cloudflare Managed Ruleset" and the "Cloudflare OWASP Core Ruleset". If a managed rule blocks legitimate requests (saving in the admin, for example), identify the rule in the security analytics screens and make an exception for that rule only.

The overall approach to WAF settings is summarized in "Protecting WordPress with the Cloudflare WAF".

Configure caching with Cache Rules, not Page Rules

As of November 2026, the official documentation marks Page Rules as deprecated. Cloudflare has announced that it will migrate existing Page Rules to newer features automatically: caching settings go to Cache Rules, security level to Configuration Rules, and forwarding to Redirect Rules (Single Redirects). Use Cache Rules for new settings.

What Cloudflare caches by default

By default, Cloudflare caches static files such as images, CSS and JavaScript based on their file extension, and does not cache HTML. So with no extra settings, WordPress admin pages and logged-in pages are never served to other people from the cache.

Example: Cache uploaded images for a long time

Create a new rule under Cache Rules in "Rules".

(http.request.uri.path contains "/wp-content/uploads/")
  • Cache eligibility: Eligible for cache
  • Edge TTL: override the origin's setting and use a long value, such as one month
  • Browser TTL: one week, for example

If you replace an image with a file of the same name, the old image keeps showing for a while. When you replace one, purge the cache for that URL from "Configuration" under "Caching" in Cloudflare.

If you also want to cache HTML

Choosing "Eligible for cache" in Cache Rules makes everything that matches the rule cacheable, HTML included. To cache WordPress HTML, you must exclude the admin (/wp-admin/), wp-login.php, logged-in users, commenters, previews and, for WooCommerce, the cart and checkout pages. A mistake in the conditions can show a logged-in user's page to other visitors, so rather than building the rules yourself, consider APO (Automatic Platform Optimization), used together with Cloudflare's official "Cloudflare" plugin, or a caching plugin that supports Cloudflare. As the official documentation states, APO requires the Cloudflare WordPress plugin.

Add security headers

With Transform Rules (no code)

With "Response Header Transform Rules" (response header modification) under Transform Rules in Cloudflare's "Rules", you can add headers to your site's responses. Choose the "Set static" operation and enter the header name and value.

Header Example value Purpose
X-Content-Type-Options nosniff Stops browsers from guessing file types
Referrer-Policy strict-origin-when-cross-origin Reduces the referrer information sent to other sites
X-Frame-Options SAMEORIGIN Prevents other sites from embedding your pages in an iframe

Content-Security-Policy can block WordPress themes and plugins as well as ad and analytics tags, so do not add it right away; check its impact with Content-Security-Policy-Report-Only first. How to add headers on the server side (.htaccess or Nginx) is covered in "How to set security headers in WordPress".

With Workers (when you need conditions)

If you need conditions, such as adding headers only to HTML or using different values per path, you can use Workers. Current Workers are written in the following ES module format (many examples still use the older addEventListener('fetch', …) style, but use this format for new Workers).

export default {
  async fetch(request, env, ctx) {
    // Get the response from the origin (including Cloudflare's cache)
    const response = await fetch(request);

    // Return anything other than HTML unchanged
    const contentType = response.headers.get('content-type') || '';
    if (!contentType.includes('text/html')) {
      return response;
    }

    // Recreate the response so its headers can be modified
    const newResponse = new Response(response.body, response);
    newResponse.headers.set('X-Content-Type-Options', 'nosniff');
    newResponse.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
    newResponse.headers.set('X-Frame-Options', 'SAMEORIGIN');
    return newResponse;
  },
};

Assign the Worker to a route on your domain (for example example.com/*) and it runs for requests to those URLs. Workers run for every request that matches the route, and requests for images and CSS count too. Check against your site's traffic that you stay within the Free plan's limit of 100,000 requests per day. If you only need to add headers, Transform Rules, which do not use Workers requests, are the better fit.

Check that caching works

Responses served through Cloudflare carry a cf-cache-status header. You can check it with curl.

# Cache status of an image (check that it becomes HIT from the second request on)
curl -sI https://example.com/wp-content/uploads/2026/11/sample.jpg | grep -i cf-cache-status

# HTML (DYNAMIC with the default settings)
curl -sI https://example.com/ | grep -i cf-cache-status
Value Meaning
HIT Served from Cloudflare's cache
MISS Not in the cache; fetched from the origin server
EXPIRED The cached copy had expired, so it was fetched again from the origin
BYPASS The cache was not used because of a setting
DYNAMIC Not eligible for caching (such as HTML by default)

This header is added to the response sent to visitors, not to the request sent to WordPress (the origin server). You cannot check the cache status from PHP, so use your browser's developer tools or curl.

Cautions when changing settings

  • After adding or changing a rule, try logging in, saving a post, submitting a contact form and (if you have one) checking out, and make sure none of them are blocked.
  • So you can roll back quickly when something goes wrong, put the purpose in each rule's name and record the date of each change.
  • If your origin server's IP address is known, attackers can bypass Cloudflare and access it directly, and the WAF and rate limiting do not apply. Restricting connections to your web ports to Cloudflare's IP addresses in the server firewall closes this gap.

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲