
Server-level caching intercepts a request before WordPress, PHP, or even Apache ever gets involved. On a CloudStick server, Nginx (nginx-cs) sits in front of everything on ports 80 and 443; when a page is cached with fastcgi_cache or proxy_cache, Nginx checks its cache store first and, on a hit, returns the stored response directly from disk or memory. PHP-FPM never spins up, Apache never proxies the request, and MariaDB never runs a query.
Redis adds a second layer alongside this: full-page caching for entire rendered responses, or object caching for individual database query results, both stored in memory for microsecond-level reads. OPcache complements both by caching compiled PHP bytecode, so the interpreter skips parsing and compiling .php files on every request that does still reach PHP. None of these three depend on WordPress knowing they exist — they operate entirely at the infrastructure layer.
Plugin-level caching happens after WordPress has already started loading. Plugins like WP Super Cache, W3 Total Cache, WP Rocket, and LiteSpeed Cache generate static HTML files from PHP output and serve those files on later requests instead of re-rendering the page from scratch. But the request still ends up in PHP's hands first.
WordPress's core bootstrap file, wp-load.php, runs enough of WordPress to reach the plugin's advanced-cache.php drop-in or an early rewrite rule, check whether a valid cached file exists, and return it. That is a partial PHP bootstrap on every single request — lighter than a full page render with database queries, but heavier than never touching PHP at all. Some plugins, including WP Rocket and LiteSpeed Cache, can offload the actual file serving to the web server through .htaccess rewrites, closing part of the gap, but none bypass PHP as completely as a cache configured directly in the web server.
Server-level caching serves pages faster because the caching decision is made in the web server layer, not the application layer. On CloudStick's stack, Nginx (nginx-cs) proxies PHP sites to Apache (apache2-cs) on 127.0.0.1:81, which then hands off to PHP-FPM over a Unix socket. A fastcgi_cache hit means Nginx never opens that proxy connection at all — it answers straight from its own cache zone in memory or on disk.
That single difference is why server-level caching handles far higher concurrent traffic on identical hardware: no PHP worker is occupied, no database connection opens, and no PHP-FPM pool slot is consumed. Under a traffic spike, a plugin-cached WordPress site is still bottlenecked by how many PHP-FPM workers exist and how fast each one can check the cache file; a server-level cached site is bottlenecked mostly by Nginx's own connection handling, which scales far higher per CPU core.
Before hand-editing fastcgi_cache rules on a CloudStick server, confirm the site actually runs on the nginx-cs → Apache → PHP-FPM path (the default for PHP and WordPress sites) rather than a directly-proxied Node.js app — the directives above only apply to the PHP proxy path, and adding them to a Node site's config will do nothing.
You want both layers together whenever a site has logged-in users, a shopping cart, or personalized content that can't be served as one static cached page. A full-page cache handles anonymous, cacheable requests — blog posts, category archives, the homepage — serving them without touching PHP at all.
Underneath that, a Redis object cache handles everything that still has to hit PHP: it caches the results of repeated database queries — post meta, options, term lookups — so that when WooCommerce checks stock levels or a logged-in user loads an account page, WordPress doesn't re-run the same query against MariaDB every single time. OPcache runs underneath both, caching compiled bytecode so every PHP execution, cached page or not, starts faster. Layering all three gives you the speed of full-page caching for the traffic that qualifies for it, and query-level speed for the traffic that doesn't.
Cache invalidation differs because plugin-level caches know about WordPress events and server-level caches don't. A caching plugin hooks into save_post, update_option, and comment actions — when a post is published, the plugin deletes or regenerates the specific static file for that page automatically, with no manual step involved.
Nginx's fastcgi_cache has no idea a post was published; it only knows a TTL, such as fastcgi_cache_valid 200 10m, or an explicit purge request sent to it. That's why server-level caching usually needs a bridge — a plugin that fires a purge request to Nginx whenever WordPress content changes, or a deliberately short TTL that accepts a few minutes of staleness in exchange for simplicity. Redis object cache invalidates differently again: WordPress's object cache API deletes specific cache keys the instant the underlying data changes, which is why it's safe to leave running indefinitely without a manual purge strategy at all.
Choose plugin-level caching alone for small, low-traffic WordPress sites where simplicity matters more than raw performance — it requires no server access and installs in a couple of clicks. Choose server-level caching, or a layered setup, once a site gets real traffic, runs WooCommerce, or serves logged-in members, because that's exactly where PHP bootstrap overhead and database load start to matter under load.
On CloudStick, this decision is largely made for you: the WordPress Manager's built-in caching optimizer configures Nginx-level page caching and Redis object caching together, correctly scoped to each site's PHP version, without hand-editing /etc/nginx-cs/extra.d/<site>.d/ configs or juggling a dozen plugin settings panels. Start with the built-in optimizer, watch the site's cache hit rate in the Web Application Logs, and only reach for an additional caching plugin if you need a WordPress-specific rule the server layer genuinely can't express.

