💡 Like BikeGremlin? Support us on Patreon
Search...

Cloudflare Cache Rules (for WordPress)

How to improve Cloudflare free tier cache, and WordPress website speed? The principle is the same for any other website, but here, we will play with WordPress in particular (I might add a section about XenForo).
Update: Cloudflare was too buggy (at least with my hosting stack) so I gave up on this after a couple of days of trying different stuff. Maybe the ideas and some solutions in this article will help someone else, someone smarter.


1. What and why?

I want to configure Cloudflare to cache HTML output of my website pages for visitors that are not logged in.

It should make the experience faster, smoother, better, and hopefully overcome the downsides of using the Cloudflare’s free tier (I’ll update this if it improves, but since 2024, Cloudflare’s free tier resulted in many 1-minute breakdowns of website connection – timeout technically).

For those interested:


2. What to cache?

I wanted to check the simplest way to know that a user is logged in. Using browser’s F12 button and dev. tools, I found this cookie (yum, yum!):

More details on how to open the dev. tools and test cache

"wordpress_logged_in" cookie
“wordpress_logged_in” cookie
Picture 1


3. Configuring Cloudflare

I logged into my Cloudflare dashboard, picked a domain, and went to:

Rules -> Overview -> + Create rule -> Cache rule

There, I could manually configure it, using the Cloudflare’s GUI.

Settings:

  • Rule name: Cache-public-html-for-non-logged-in-Relja01
    (or something nicer and shorter 🙂 )
  • If incoming requests match…: Custom filter expression
FieldOperatorValue
Cookiedoes not containwordpress_logged_inAND
URI Pathdoes not contain/wp-adminAND
URI Pathdoes not contain/wp-loginAND
URI Path *does not start with/z
Note: instead of the “wordpress_logged_in” value, you could use something shorter like “logged_in”
* this rule is for troubleshooting – see section 4.1 for details
Table 1
  • Then…
    Cache eligibility (required): Eligible for cache
  • Edge TTL: Ignore cache-control header and use this TTL – 1 day
    (or whatever you prefer, I would start with a short period for testing)
  • Browser TTL: Override origin and use this TTL – 2 hours
    (shorter than Edge TTL)

DISABLE Serve stale content while revalidating (Optional): I set this to disabled (to NOT serve stale before revalidated)


4. Testing

This is very important – confirming that it does not cache for the logged in users, and that it does cache for the non-logged in (guest) visitors.

F12, network, and check the
Network -> Headers
for both logged in, and non-logged in (incognito windows should do the job for the latter).

Logged in testing should show:

  • Cf-Cache-Status: DYNAMIC
    Means Cloudflare is bypassing caching.
  • X-Litespeed-Cache-Control: no-cache
    If you are using LiteSpeed too, and set it to not cache logged in users.
  • Cache-Control: no-cache, no-store, must-revalidate, max-age=0
    This tells browsers and proxies not to cache this content.

Non-logged in (guest visitor) testing should show:

  • Cf-Cache-Status: HIT
    Cloudflare served the page from its edge cache – success!
  • X-Litespeed-Cache-Control: no-cache or hit
    This depends on whether the page was also cached by LiteSpeed – if you never see “hit” check your LiteSpeed configuration.
  • Cache-Control: max-age=7200
    Public browsers and Cloudflare will cache this page for 2 hours. Matches my test TTL.
  • age: 1024
    Number of seconds since the page was last cached on Cloudflare’s edge (yes, I did get this result when I checked that particular test page for writing this tutorial LOL 🙂 ).


4.1. Troubleshooting WordPress implementation

Problems with Imunify 360 giving more false positives!
I added the rule:
URI Path | does not start with | /z
Similarly to XenForo, this still isn’t working perfectly, and after a few days of testing and trying I gave up on this. Cloudflare is too buggy.

I wanted to automate page updates. And I am using LiteSpeed cache plugin. So, I started by creating a Cloudflare API Token, and adding it to LiteSpeed CDN options.
There are other ways to automate this – writing some child theme custom code, writing a plugin etc, but I wanted to try this first.

Cloudflare has a WordPress template when you are creating a new token.

Cloudflare WordPress API Token template
Cloudflare WordPress API Token template
Picture 2

I need to test this to see if and how well it works. 🙂


5. Conclusion and downsides

Cloudflare does add some complexity, but it can also help. Use it wisely, and always be prepared to ditch it (which is why LiteSpeed for WordPress – and XenForo for that matter – is a good idea).

One downside of this method is that for any article update, I must manually purge the cached page version (or wait for the set Cloudflare cache to expire):
Caching -> Configuration -> Custom Purge -> Copy-paste the updated page

Updated – see below for the added XenForo section. 🙂


6. Appendix – XenForo

Let’s give XenForo a try, shall we (hoping to be corrected if I get things wrong)? 🙂

Se section 6.69 – I gave up, Cloudflare has become too buggy.


6.1. Cache pages for guests

The cookie that is present for logged in users, and isn’t present for guests/incognito is: “xf_lscxf_logged_in” (set by my caching plugin – no other reliable logged-in cookie gets set by the XenForo software, unfortunately).

So, the principle is the same as shown above for WordPress, but with different conditions.

FieldOperatorValue
Cookiedoes not containxf_sessionAND
URI Pathdoes not contain/login/AND
URI Pathdoes not contain/logout/AND
URI Pathdoes not contain/admin.phpAND
URI Pathdoes not start with/z
Table 2

This rule avoids caching pages served to users who are:

  • In the process of logging in.
  • Already logged in.
  • Using forms
    (because all those generate xf_session – see more about the XenForo cookies)

For the forum, logged in users will see the latest info, and only guest visitors will see the stale cached versions. However, as the forum is more frequently updated with new comments and posts, unlike my websites where only I manually edit and add stuff, I’ve set the Cloudflare cache expiry to a shorter period.


6.2. Cache CSS for everyone

Another cache rule – read from XenForo community forum by user Digitalpoint, quote (this only caches CSS, so no need to use cookies):

“For a URL match of YourXenForoInstallation.com/css.php?css=, give it a long Browser Cache TTL, set Cache Level to “Cache Everything”, give it a long Edge Cache TTL and enable Origin Cache Control. This will allow XenForo’s CSS to be cached in user’s browser and the network edge.”

I set this last one under:
Rules -> Page Rules
Browser Cache TTL: 8 days, Cache Level: Cache Everything, Edge Cache TTL: 7 days, Origin Cache Control: On

The above sticken rule is now being set as obsolete in Cloudflare (I expect it to be disabled pretty soon). So, I configured a separate rule in the Cache rules page (as shown above for WordPress and XenForo.

FieldOperatorValue
URI Pathcontains/css.php?css=AND
Cookiecontainsxf_lscxf_logged_in
Table 3

Here, I am relying on my LiteSpeed XenForo addon – as it seems to be the only thing that reliably sets cookes for logged in users, in every situation (the cookie “xf_lscxf_logged_in” is set by that plugin for logged in users only).


6.69. Update/troubleshooting XenForo implementation

Problems with Imunify 360 giving more false positives – still not fixed!
To fix the problems and prevent caching of Imunify challenge pages, I added a rule:
URI Path | does not start with | /z
That couldn’t solve all the problems, funny page resolving and not opening links on occasions. So, I gave up. The text below (and above) shows my efforts to make it work.

Upon further testing, I noticed that a stale page version is shown to logged in user(s) if they open the forum after several hours or similar. Once a page is refreshed, the problem was gone.

I also noticed that dark page mode was cached for some pages, light mode for others (probably depending on what mode users used when the page was first requested for caching). I used a “Solomon’s” solution of simply disabling the dark mode (to make the layout and design more consistent). Will see if many members request and prefer the dark mode.

This was probably because Cloudflare didn’t get any info from the browser until a page is refreshed, and browser showed a cached version.

To fix that problem, I had to make browser “force” fresh page for logged in users, “telling” Cloudflare that it’s a logged in browser with a cookie. So, I went to:
Appearance -> Templates -> PAGE_CONTAINER

There, I found the closing </body> tag and added this code just above it:
(I already had horizontal scroll bar code there from before, so this went beneath it)

<!-- BEGIN BikeGremlin force reload if back/forward cache caused a stale guest view -->

<xf:if is="$xf.visitor.user_id">
<script>
  (function () {
    const cookies = document.cookie;
    const isBackNav = performance && performance.navigation && performance.navigation.type === 2;

    // If page was loaded from bfcache and user is logged in, force reload to get fresh content
    if (isBackNav && cookies.includes("xf_lscxf_logged_in=1")) {
      window.location.reload(true);
    }
  })();
</script>
</xf:if>

<!-- END BikeGremlin force reload if back/forward cache caused a stale guest view -->

Will further test this to confirm it’s all good.


Last updated:


Originally published:




Please use the BikeGremlin.net forum for any comments or questions.

If you've found any errors or lacking information in the article(s) - please let me know by commenting on the BikeGremlin forum or by sending a message via the forum's contact form.
You can comment anonymously (by registering with any name/nickname), but I think it is good to publicly document all the article additions (and especially corrections) - even if their author chooses to remain anonymous.

Tools and other products that I use (and can recommend)

TOC