Why I Moved Away From Cloudflare Caching And Back To FastCGI

Earlier that week my website had been through two separate periods of downtime. One was caused by a caching issue and the other was caused by a wider Cloudflare outage. Neither incident caused any serious damage, however they did make me look again at how many services were sitting between the server and the person trying to load the site. In that setup, a normal request was no longer just passing through WordPress and the server I controlled, it also depended on configuration and behaviour outside of that environment.

I still like Cloudflare and I still use several of its services. This was not a reaction against Cloudflare as a company, or a decision based on one bad week. Performance still mattered, but predictability was the part I kept coming back to. If my website needed caching, I wanted to know where the cache lived, how it was being created, how it was being cleared and how quickly I could rebuild the same setup on another server.

That line of thinking pulled me back towards the server. I have always enjoyed infrastructure work because the closer I am to the server itself, the fewer parts of the setup feel vague. That does not automatically make a server-level decision the right decision, because there are plenty of cases where an external service is the better choice. In this case, though, I wanted the caching layer to be something I could inspect, recreate and understand without having to remember a collection of dashboard settings from months earlier.

Looking Beyond WordPress Plugins

The obvious next move would have been to install another WordPress caching plugin. WP Rocket, WP Fastest Cache and similar tools can do a good job, and I have no issue with using them when they fit the project. I was not looking for another plugin though. I was trying to move the caching layer closer to the server, partly for speed, but mostly because I wanted the behaviour to be repeatable.

That repeatability mattered more than I first expected. If I moved the site to another server, I wanted the caching to behave in the same way without spending an afternoon rebuilding settings inside WordPress. Plugin configuration can be perfectly fine on one site and slightly awkward on another, especially once themes, logged-in users, redirects and dynamic pages are involved. I wanted the caching rules to live with the server configuration, where I could read them, version them and understand them as part of the environment.

Once I started thinking about it that way, FastCGI caching became the most interesting option. My preferred server setup has usually been NGINX, so it made sense to look at what NGINX could already do before adding another layer. I was not trying to create a complicated setup for the sake of it. I wanted the simplest caching arrangement I could trust, and FastCGI felt like the right place to start.

Redis Was Interesting, But It Was Not The First Problem

Redis came up early because it appears in a lot of WordPress performance discussions. I spent some time reading around it and I still think it has a place in the stack, particularly when object caching and database queries start becoming more important. The more I looked at it, though, the more I realised it was not the first problem I needed to solve. I was dealing with page caching, not object caching.

That distinction changed the direction of the work. Redis might help WordPress avoid repeating certain database work, but it was not going to replace the need for a fast, predictable way to serve full pages. I wanted NGINX to be able to serve a cached page before WordPress had to do anything. For that particular problem, FastCGI caching was a much closer fit.

I did not rule Redis out. I just parked it. At that stage, adding Redis would have given me another moving part before I had properly dealt with the page cache itself. I wanted to get one layer working properly, understand its behaviour, then decide whether the next layer was worth adding.

Reading Before Changing The Server

I could have generated a configuration file with ChatGPT and probably had something working quickly. Instead, I spent time reading the NGINX documentation, LinuxBabe articles and several configuration examples to understand what each directive was actually doing. That took longer, but it felt like the right way to approach something that would sit between the visitor and WordPress on every request. I did not want to copy a block of configuration and only understand it after something went wrong.

That probably comes from how I first learned to use computers. I grew up around MS-DOS, QuickBasic and command-line environments, so opening an SSH session and working directly on a Linux server still feels normal to me. I like seeing where things live on disk, what process is responsible for them and what happens when a request moves through the system. With caching, that matters because a small misunderstanding can leave you serving old content without realising it.

After a few hours I had the basic structure in place. There was a cache directory, a cache zone and an NGINX configuration that could serve cached content through FastCGI. The configuration itself was not especially complicated. The useful part was understanding why it worked, because that gave me something to build on when the first problem appeared.

The Cache Worked, Then WordPress Changed

The first round of testing looked good. Pages were loading quickly, the response headers showed the cache status I expected and repeated requests were being served from cache. From the server’s point of view, the setup was doing exactly what I had asked it to do. Then I updated some content inside WordPress and refreshed the page.

The old version was still there. My first assumption was that I had made a mistake in the configuration, so I went back through the rules and checked what NGINX was doing. After a bit of testing, the answer was simpler than that. The cache was not broken, it was behaving exactly as configured.

NGINX did not know that I had changed a page in WordPress. It had a valid cached version available, so it served that version. WordPress knew the content had changed, but NGINX had no reason to care unless I gave it a rule or process that connected those two things. Retrospectively, that sounds obvious, but it was the point where the project became more than just enabling a cache.

That was the difference I had to solve. WordPress understands posts, pages, logged-in users, admin screens and content changes. NGINX understands requests, locations, headers and files on disk. The cache had to sit between those two worlds without accidentally making the website feel broken.

Making NGINX Behave Around WordPress

The next stage was less about speed and more about behaviour. The admin area needed to bypass the cache, logged-in users needed fresh content and dynamic requests could not be treated the same way as ordinary public pages. Search pages and feeds also needed their own rules. None of that was difficult in isolation, but each rule needed testing because one careless cache rule can create a strange problem later.

This was where the work became more useful than the performance gain. A lot of tutorials stop once a cached page is being served, but that is only the first part of the job. A website is not just a collection of public pages. It has editors, sessions, previews, forms, changing content and parts of WordPress that should never be cached as if they were static HTML.

I went through several rounds of testing and adjustment. I checked cache misses on first requests, cache hits on repeated requests and fresh responses when I was logged in. I tested updates from WordPress and watched how the server responded. Slowly the setup started to feel less like an experiment and more like something I could rely on.

Once those rules were in place, the behaviour made sense. Public pages could be served quickly from the cache, while the parts of the site that needed to remain fresh continued to pass through WordPress. That was the point where I felt the configuration was solid. Not finished, but solid enough that I understood the decisions behind it.

Cache Purging Became The Part That Mattered

The last part I had to think through was cache purging. A cache is only helpful while it serves the right version of a page. If it keeps serving old content after a page has changed, the speed no longer matters because the visitor is seeing the wrong thing. At first I handled that manually by clearing the cache and letting it rebuild.

That worked, but it was not a good long-term answer. I did not want publishing a page in WordPress to become a two-step process where I also had to remember to clear something on the server. In daily use, that kind of setup eventually fails because someone forgets, or because I come back to the site months later and have to remind myself how everything works. The cache needed to be cleared automatically when WordPress changed something important.

That led me into WordPress-side cache purging. There are tools that help with FastCGI cache invalidation, and some of them worked reasonably well. Even then, I wanted to understand what they were doing behind the scenes. If a page failed to update, I wanted to know whether the problem was WordPress, NGINX, the purge request or the files sitting inside the cache directory.

That need to see the moving parts probably shaped the whole project. I was not trying to hide the caching behind another interface. I wanted fewer surprises. The more I understood about how the cache was created and cleared, the more comfortable I felt using it.

What I Took From The Move Back To FastCGI

Looking back, I do not think this was only about caching. The caching work was the visible part, but the real reason for doing it was to reduce the number of things I had to trust without fully understanding them. Websites tend to collect dependencies over time. A plugin gets added for one reason, a service gets added for another, then months later a fairly simple site depends on more external behaviour than I originally intended.

Sometimes that is fine. I still use external services where they make sense, and I am not interested in moving everything back to the server just to prove a point. In this case, though, caching felt like something I wanted closer to the environment I already managed. The server was already responsible for serving the site, so letting it handle the page cache felt like a cleaner fit.

FastCGI gave me the setup I wanted. The cache lives on the server, the rules live in the NGINX configuration and the behaviour can be recreated on another environment without digging through old plugin settings. If I need to inspect it, I know where to look. If I need to change it, I know which part of the configuration is responsible.

There is still more I want to explore. Redis is still interesting, especially for object caching, and I can see room for better cache management in future deployments. For now, though, the site is fast, the caching layer is predictable and I understand how it behaves when WordPress changes underneath it. That was the part I wanted back.