Ahosting Logo
Knowledge Base

Compression and Cache Headers in cPanel

Compression and caching save different downloadsCompressionCache headersWhat it savesmakes the first download smallerprevents the second download entirelyApplies totext: HTML, CSS, JavaScriptanything the browser may keepBigger win ona first visitany site people return toThe risknone worth worrying aboutserving a stale file for a long timeLong caching is safe only when the filename changes with the content. Without that, cache a short time.

Two headers decide how much data a visitor actually downloads and how much they download again on a second visit: compression, and cache control. Both are configured once, both are free, and both are frequently absent on sites that have otherwise been optimised carefully.

Compression

Text-based files: HTML, CSS, JavaScript, JSON, SVG, compress substantially, often to a quarter of their size. The server compresses, the browser decompresses, and the visitor downloads far less.

In cPanel, Optimize Website enables it. Compress all content is the sensible setting; the alternative of listing specific MIME types is more work and easy to leave incomplete.

Confirm it is actually happening rather than assuming:

curl -I -H "Accept-Encoding: gzip" https://example.com

A content-encoding header in the response means it is on.

Do not compress images and video

JPEG, PNG, WebP, MP4 and similar are already compressed. Compressing them again achieves nothing measurable and costs processing on every request.

Compress-all settings generally exclude these correctly. If you are listing types by hand, list the text ones and leave media alone.

Cache headers

Compression reduces the first download. Cache headers prevent the second one entirely, which is the larger saving on any site people visit more than once.

The header tells the browser how long it may reuse a file without asking again. In .htaccess:

<IfModule mod_expires.c>
 ExpiresActive On
 ExpiresByType image/jpeg "access plus 1 year"
 ExpiresByType image/png "access plus 1 year"
 ExpiresByType image/webp "access plus 1 year"
 ExpiresByType text/css "access plus 1 month"
 ExpiresByType application/javascript "access plus 1 month"
 ExpiresDefault "access plus 2 days"
</IfModule>

Take a copy of .htaccess before editing. A syntax error there produces a 500 across the whole site.

The trade, and how to avoid it

A long cache time means returning visitors get the file instantly and do not see your changes until it expires.

The standard resolution is versioned filenames, style.css?v=7 or style.a3f9.css. The URL changes when the content changes, so the browser fetches the new one immediately while the old URL stays cached harmlessly.

Most content management systems and build tools do this automatically. If yours does, long cache times on assets are safe. If it does not, that is the thing to fix before extending cache times: otherwise you will be telling visitors to clear their cache, which is not a plan.

Never cache HTML aggressively

Images and stylesheets can be cached for a year because their URLs change when they change. HTML pages keep the same URL and their content changes, so a long cache time means visitors see stale pages with no way to know.

A short time or no caching at all is correct for HTML. Page caching at the server is a different mechanism and does not have this problem, because the server controls when the cached copy is discarded. Optimizing WordPress performance picks it up from there.

These are not a substitute for smaller files

Compression makes a large file smaller to transfer. It does not make an oversized image appropriate.

A photograph uploaded at camera resolution and displayed at 400 pixels wide is the largest thing on most pages, and no header fixes it. Resizing before upload and using a modern format saves more than compression and caching combined on a typical site.

Do the headers because they are free and permanent. Then do the images, because that is where the weight actually is.

Measure both

Load a page with the browser's network panel open and look at two things: whether responses show a content encoding, and what the total transferred size is.

Then reload and check how much came from cache rather than the network. A second visit that transfers almost nothing means the cache headers are working; one that re-downloads everything means they are not, whatever the configuration says.

Confirm what is actually being sent

Both settings are easy to configure and easy to configure ineffectively, and one command shows the truth.

curl -sI -H 'Accept-Encoding: gzip, br' https://example.com/style.css | grep -iE 'content-encoding|cache-control|expires|vary'

Three things to check. Content-Encoding present means compression is working for that file type, and its absence on CSS while present on HTML means the type list is incomplete.

Cache-Control is what browsers actually follow; Expires is the older header and is ignored when both are present. Setting only the second is a common way to configure caching that does nothing.

And Vary: Accept-Encoding should accompany compression, or an intermediate cache may serve a compressed response to a client that cannot read it.

Test the file types individually

Compression applies per content type, and the list frequently omits the ones added since it was written.

for f in / style.css script.js data.json icon.svg font.woff2; do
 printf '%-14s %s\n' "$f" "$(curl -sI -H 'Accept-Encoding: gzip' "https://example.com/$f" | grep -i content-encoding | tr -d '\r')"
done

JSON and SVG are the usual omissions. Both are text and both compress substantially, and neither is in older default configurations.

WOFF2 fonts are already compressed and should show nothing; compressing them again costs processing for no gain, which is the same mistake as compressing images.

Immutable is the setting worth knowing

A long cache lifetime still permits the browser to revalidate, asking whether the file changed on every page load, which is a round trip even when the answer is no.

Header set Cache-Control "public, max-age=31536000, immutable"

immutable tells the browser not to ask at all for the stated period. On a site with many assets that removes a measurable number of requests on repeat visits.

It is safe only for files whose name changes when their contents change: the hashed filenames a build tool produces. Applying it to a file with a fixed name means visitors keep an old version for a year with no way to update it. Hosting a static site correctly walks through that arrangement.

Where the headers are set decides which wins

Cache headers can come from several places at once: the server configuration, an .htaccess rule, a caching plugin, and any CDN in front.

When they disagree, the result is whichever spoke last, and a CDN frequently overrides everything behind it, which is why a setting that appears correct on the origin has no effect for visitors.

Check from outside the CDN as well as through it. The two answers differing is the finding, and it explains most cases where caching is configured and behaving as though it is not. Choosing and setting up a CDN walks through the layer.