Skip to content

Speed Optimizations

A WordPress site on CorePanel can be sped up at the web-server level, without a caching plugin, a build step or a single change to the site’s code. Four of the switches are transformations of what the site returns; the fifth — the dynamic page cache — skips building the page at all, and is the one that turns a server that dies at 20 visitors into one that serves thousands.

This page is the operating manual: what to enable, in what order, how to prove it is working, how to turn it off, and what each failure looks like from the panel. The reference for each individual switch — and the benchmarks — lives in Web Optimizations; how the plugin decides what may be cached is in the cache module.

SwitchWhat it doesEditions
Automatic WebPServes images as WebP to browsers that accept itAll, including Personal
Early HintsAnnounces a page’s key assets while PHP is still building itAll, including Personal
Minify JS / CSSStrips whitespace and comments on the way outSpeed Optimizer — Pro and above
Dynamic page cacheAnswers a repeat visitor without running PHP at allSpeed Optimizer — Pro and above

Everything here is per site. A hosting account with a primary domain, an addon domain and two subdomains has four independent sets of switches, and nothing is inherited between them: turning the cache on for example.com leaves blog.example.com exactly as it was.

Five things decide whether this will work at all. Check them once, at the beginning, and most of the troubleshooting section below never applies to you.

  1. The edition. WebP and Early Hints are in every edition. Minification and the page cache are the Speed Optimizer, which needs Pro or Business. On Personal those rows are shown locked in your panel, and are not rendered at all in a customer’s.
  2. CorePanel must know the site is WordPress. The page cache installs its companion plugin into the WordPress instances CorePanel manages. A site that was copied in by hand and never scanned is, as far as the cache is concerned, not WordPress — see Adopting sites that are already there, or run corepanel wp scan <account>.
  3. Not on an alias. An alias (parked) domain serves a copy of another domain’s site, and WordPress invalidates by path — it never learns which hostname the visitor came through. CorePanel refuses to cache one. Enable it on the domain the alias points to; the other optimizations work on an alias normally.
  4. One page cache at a time. If WP Rocket, LiteSpeed Cache, W3 Total Cache, WP Super Cache, WP Fastest Cache or Cache Enabler is active, CorePanel’s companion stands down and declares nothing — two page caches fight over the same output buffer. Remove the plugin cache first.
  5. A site that is being edited is a site to leave alone. The cache is safe during a redesign, but comparing before-and-after numbers while a theme changes underneath you proves nothing.

In the panel, open the account and go to Optimizations. The selector at the top right picks which of the account’s sites you are configuring — every domain, addon, alias and subdomain is listed, each with its own settings.

Mockup of CorePanel&#x27;s Optimizations section for example.com: a site selector in the header, Automatic WebP forced On and Early Hints left on Default with Default/On/Off segmented controls, then a Speed Optimizer group with Minify JavaScript and Minify CSS switched on, and a Dynamic page cache control set to Evaluate showing the evaluation report — 83% of cacheable requests would be served from cache, 12% of all traffic could never be cached, and a breakdown listing state-cookie 402, no-contract 190 and set-cookie 82.

Customers with access to the client panel get the same section for their own sites, under Websites. Everything in this guide applies to them too.

Each switch takes effect on the next request — the site file is rewritten and the web server reloads, with no downtime and no restart of anything the visitor can notice.

Turning them on, in an order that stays boring

Section titled “Turning them on, in an order that stays boring”

Enable them one at a time, in this order, and check the site after each. The order is not arbitrary: it goes from the change least likely to be visible to the one that changes what a visitor is actually served.

Set it to On. It is the largest single win on an image-heavy site, it costs nothing, and it cannot break a page: browsers that do not accept WebP keep receiving the original file, and the files in the document root are never touched.

Terminal window
corepanel domain optimizations set example.com --webp on

How much it saves is decided by what was uploaded. Flat graphics — screenshots, logos, exports — are what PNG handles worst and WebP best; photographs that were already exported sensibly give up far less. The measured range is here.

Leave it on Default (which is on) unless you have a reason not to. It only affects responses that take time to build — PHP-FPM and proxied backends — and lets the browser start fetching the stylesheet while WordPress is still working.

Turn on Minify CSS, load the site, then turn on Minify JavaScript and load it again. Two separate steps, because if something breaks you want to know which one did it.

Terminal window
corepanel domain optimizations set example.com --minify-css on
corepanel domain optimizations set example.com --minify-js on

Minification is generally safe, but it is a transformation of what your application returns. Sites that depend on the exact bytes of a script — an integrity hash, an inline source map — are the ones that notice.

Do not go straight to On. Set the cache to Evaluate and leave it there for a few days of real traffic.

Terminal window
corepanel domain optimizations set example.com --page-cache shadow

In Evaluate the cache decides and stores exactly as it would in production, and serves none of it. Visitors get the same site they got yesterday. What you gain is the only honest answer to “is this worth it for this site”, which cannot be guessed from the outside: a news site and a membership site with identical traffic land in completely different places.

This is also the step that installs the companion plugin — see what switching it on actually does below.

While a site is evaluating, the Optimizations section shows what the cache is finding, and the CLI reports the same numbers for every site being measured:

Terminal window
corepanel cache stats # every site under evaluation, busiest first
corepanel cache stats example.com # just this one
HOSTNAME REQUESTS HIT% BYPASS% TOP BYPASS REASON
example.com 5614 83.4 12.0 state-cookie (402)

Two numbers, kept deliberately apart:

  • HIT% — of the traffic the cache could serve, how much it would have served from cache. This is the number that says whether switching it on is worth it.
  • BYPASS% — how much of all traffic could never be cached at all. A shop where every visitor carries a cart is not a site with a bad cache; it is a site the cache cannot help.

A site above roughly 60% HIT% with a low bypass share will feel dramatically faster. A site whose bypass share is most of its traffic will not, and no setting will change that — what the reasons mean is below.

When the numbers say yes:

Terminal window
corepanel domain optimizations set example.com --page-cache on

Leaving Evaluate is clean: everything stored while evaluating is discarded rather than served, so nothing built under rules you were still testing ever reaches a visitor. The only cost is that those pages are generated once more.

Four things happen, and knowing them is most of the troubleshooting:

  1. The site file gains a cache configuration and the web server reloads. The only caching policy CorePanel ever writes is the application decides: the engine stores a page when, and only when, WordPress declares that page shareable.

  2. The companion plugin is installed or refreshed at wp-content/mu-plugins/corepanel.php, in every WordPress instance that belongs to this site. It is the same must-use plugin that already provides one-time login links and hardening; if the site had it, it is brought up to date.

  3. The site is told the cache is running, per request, through two FastCGI parameters. Without them the plugin registers no hooks at all — which is why having it installed on every managed site costs nothing, and why enabling the cache later needs no visit to the site.

  4. Invalidation starts flowing back. Publishing, editing or deleting a post drops its permalink, the front page, its archives, the feed and the sitemaps; a comment drops the page it lives on; a theme switch, a plugin activation or a permalink change drops everything. The signal travels on the very response that made the change, including the admin POST that is never itself cached.

  5. Updates drop everything too. Updating a plugin or a theme — from the panel’s WordPress section, or from the plugins list in wp-admin — empties that site’s cache, and so does rolling the site back to a restore point. Updates run from the panel have no page load to carry the signal, so the panel empties the cache itself once the update succeeds.

    Updating WordPress itself is the one case where the signal cannot ride the update’s own page — by then it has already started printing — so it is carried by the next screen you open in wp-admin, normally the very next click. An automatic update from cron has no page at all, so the site fetches one of its own and empties the cache within the run.

Pages are stored with a lifetime of up to a year, which is only safe because freshness comes from that invalidation rather than from a timer. The plugin also caps a page’s lifetime whenever it mints a WordPress nonce, so a cached page can never hand out a security token that has already expired.

While the site is evaluating, the engine reports its verdict in a response header. This is the only mode that emits it:

Terminal window
curl -sI 'https://example.com/' | grep -i x-px-cache
X-Px-Cache: would-hit

The values are would-hit, would-miss and bypass:<reason> — the same vocabulary the report counts. Fetch a page twice: the first request is a would-miss, the second should be a would-hit. A bypass: on a plain anonymous page view is the interesting case, and the reasons are below.

With the cache On there is no such header — a live site does not advertise its cache state to visitors — so measure the thing you actually care about instead:

Terminal window
curl -s -o /dev/null -w 'ttfb %{time_starttransfer}s\n' 'https://example.com/'
curl -s -o /dev/null -w 'ttfb %{time_starttransfer}s\n' 'https://example.com/'

The second call should come back in single-digit milliseconds plus your network latency. If both calls are equally slow, the page is not being served from cache; start at the cache is on and nothing got faster.

The safety check worth doing once, on any site with logins: sign in, load a page you know is cached, and confirm you see your admin bar and your own content. A logged-in visitor is never served a cached page — this is enforced in the plugin and independently in the engine, which refuses to store any response that sets a cookie.

Nothing. WordPress refreshes its own cached pages as content changes, so a site publishing posts, taking comments and updating plugins keeps itself fresh without anyone touching the panel.

What WordPress cannot signal is a change it never saw:

  • a theme or template edited over SFTP or in the file manager,
  • a database restored underneath the site,
  • a page that was cached while something was already wrong.

For those, Empty cache in the Optimizations section drops every stored page for the selected site. The button only appears while the cache is On. From the CLI:

Terminal window
corepanel cache purge example.com # the whole site
corepanel cache purge blog.example.com / /feed # just those pages
corepanel cache purge example.com "/2026/*" # everything under a prefix

Two things worth knowing. Every hostname of the site is emptied, not just the one you named — a page is stored once per hostname a visitor arrived through, so example.com and www.example.com hold separate copies; the panel and the CLI both report the hostnames they reached. And emptying the cache is never blocked, even on a server whose licence has lapsed: being unable to clear a wrong page is not an acceptable way to be reminded of a renewal.

Clearing the cache costs the next visitor to each page one normal, uncached page load. There is no other side effect.

What you wantHow
Stop serving cached pages for a siteSet the page cache to Off (--page-cache off). Effective on the next request; stored copies stop being reachable.
Stop caching one WordPress site from inside WordPressdefine( 'COREPANEL_CACHE_OFF', true ); in wp-config.php. Hardening and login links keep working.
Rule the companion plugin out entirely while diagnosingdefine( 'COREPANEL_MU_OFF', true ); in wp-config.php. This also disables hardening and one-time login links.
Keep a specific page out of the cacheadd_filter( 'corepanel_cache_public', '__return_false' ); on that page — see the filters
Undo minificationSwitch Minify CSS / Minify JavaScript off

If you turn the cache off and on again around a change, empty the cache afterwards. It costs one uncached load per page and removes any doubt about what is stored.

SymptomMost likely causeWhat to do
Cache is On, nothing got fasterThe companion plugin is not answeringSee below
no-contract dominates the reportSame, or the traffic is admin/RESTSee below
state-cookie dominatesVisitors are logged in or carrying a cartNothing to fix — the cache cannot help that traffic
set-cookie dominatesA plugin issues a cookie on every responseIdentify it; the engine will never store those responses
vary dominatesA plugin emits Vary: Cookie indiscriminatelyThe report names the field; a per-visitor Vary cannot be cached
Old content after an SFTP or database changeWordPress never saw the changeEmpty cache for that site
www still shows the old pageEach hostname stores its own copyPurge reports the hostnames it reached; if one is missing it is a separate site
A form stopped submittingA stale security tokenSee below
Site looks wrong after enabling minifyAn asset that must not be rewrittenTurn Minify JS off, then CSS, to find which
The page cache row is missingPersonal edition, or the site is an aliasPro or Business; enable it on the domain the alias points to
”The Speed Optimizer requires CorePanel Pro or Business”The licence does not include itTurning something off is always allowed, even unlicensed
The report is emptyNo traffic yet, the server restarted, or the site is already OnCounters only run under Evaluate

This is the failure this feature can produce that leaves no trace in any log, and it has one cause with four flavours: the companion plugin is not speaking, so every page is bypassed as no-contract and the cache stores nothing at all.

Work down the list:

  1. Is the site a managed WordPress instance? Open WordPress in the panel and look for it. If it is not listed, the plugin was never installed there — run a scan (corepanel wp scan <account>) and enable the cache again.
  2. Is the instance attributed to this hostname? The plugin goes into the WordPress under this site’s document root. A WordPress living under a subdomain’s docroot belongs to the subdomain, and must have the cache enabled on the subdomain.
  3. Is the file there? Check wp-content/mu-plugins/corepanel.php. Reinstalling WordPress or a migration that skipped mu-plugins removes it. Any of these puts it back: re-applying the cache mode from the CLI, toggling the mode in the panel, applying hardening, or clicking Log in.
  4. Is something disabling it? COREPANEL_CACHE_OFF or COREPANEL_MU_OFF in wp-config.php, or another page-cache plugin still active — the module stands down for both.

The quickest confirmation is Evaluate mode: set the cache to Evaluate, fetch a page twice and read X-Px-Cache. A bypass:no-contract on an ordinary anonymous page view means the plugin is not running; a would-hit means it is.

The report names why requests could not be cached, busiest first. The ones that come up:

ReasonMeaning
state-cookieThe visitor is logged in, has a cart, or carries another state cookie. Normal, and the honest ceiling on a shop or a membership site.
no-contractNothing declared the response cacheable. On a WordPress site with the plugin running this is normal for wp-admin, REST, AJAX and XML-RPC traffic, which never reach the page path at all — so a share of no-contract is expected. A site where it dominates the front-end is the case above.
set-cookieThe response issued a cookie of its own. The engine never stores those, whatever the application says.
varyThe response declared it varies on something the cache cannot distinguish. The report breaks it down by field: a language or encoding header can be handled; Cookie cannot.

The report lists these names on their own; the X-Px-Cache header prefixes them, so the same finding reads as bypass:no-contract on the wire.

Reasons the plugin declares on purpose — searches, previews, password-protected posts, visitors who have left a comment, 404s, cart, checkout and account pages — are working as intended, not problems to solve.

WordPress security tokens expire, and a page cached for a long time could hand out a dead one. CorePanel already caps a cached page’s lifetime a minute short of the token inside it, so this should not happen — but a plugin that mints its own token with its own lifetime is outside that rule.

Empty the cache to confirm the diagnosis: if the form works right after a purge and fails again later, that is what it is. Fix it by shortening the page’s lifetime, or by keeping it out of the cache:

// This page: cache for an hour instead of the default.
add_filter( 'corepanel_cache_max_age', function () { return HOUR_IN_SECONDS; } );

Prices in the wrong currency, a greeting with somebody else’s name, a members-only block on an anonymous page. A plugin is personalising the page through a cookie, and CorePanel does not know that cookie means “this visitor is different”.

The session, comment, WooCommerce and Aelia currency cookies are already handled. For anything else, name the cookie and the site stops sharing those pages at once:

Terminal window
corepanel domain optimizations set shop.example.com --state-cookies "my_currency"

Full detail — including why the list survives your other setting changes, and what it costs — is in Cookies that mean “this visitor is different”.

A banner that decides in PHP what the page contains turns one URL into two different pages, and only one gets stored. The companion recognises Cookie Notice & Compliance and CookieYes in its legacy mode and stops caching those sites outright, because the alternative is serving tracking tags to visitors who refused them. Complianz, Real Cookie Banner and CookieYes on its web app block in the browser and cache normally.

For any other banner, the one-minute test fetches the page with and without the consent cookie and diffs the two.

  • It does not cache non-WordPress sites. Without an application that can say what is shareable and which URLs went stale, the honest answer is not to cache. Enabling the mode on such a site is harmless — nothing is stored, nothing is served from cache — but it changes nothing either.
  • It does not cache alias domains, for the reason in Before you start.
  • It does not shorten how long your content is wrong. It shortens how long each page takes to serve. When you publish, the affected URLs are dropped immediately.
  • It is not a CDN. Pages are served from your server, close to your server. What changes is that serving one costs about a millisecond of CPU instead of a quarter of a second.
  • A store or a membership site will see a smaller win than a blog, because much more of its traffic is personal to each visitor. That is the cache working correctly.
  • Web Optimizations — the reference for each switch, and the measured numbers on a 2-vCPU server
  • Security and Hardening — what the companion plugin declares, its filters and its escape hatches
  • Web Traffic — what your server is actually serving, before and after
  • CLI referencedomain optimizations, subdomain optimizations and cache