20 October 2021

When someone views a page on your website lots of resources are downloaded. A typical page is made up of HTML, CSS, JavaScript and resources such as images. Many of these resources can be compressed before they are sent to the visitor’s web browsers. This saves bandwidth and makes your website load faster.

How compression works

You can use your web browser’s develop tools to check all the resources for an individual page. The below image shows the resources for a very basic WordPress website. The first entry is for the main document and the other entries are for individual resources, such as style sheets and scripts.

The 'Network' tab in your web browser's developer tools lets you view all requests for a web page, including the request headers.
Viewing request headers.

When your browsers requests a page it sends various requests headers. You can see those by selecting a resource. For instance, in the above image I selected the style.css file. One of the request headers is Accept-Encoding. This tells the server which types of content encoding it understands. If the client supports a compression algorithm which the server supports then the content can be compressed before it is sent to the client.

The two most common encoding methods are gzip and deflate. The latter is enabled by default on Apache servers. It uses two modules: mod_filter and mod_deflate. Either way, the server looks at the request headers, and if it is configured to use compression it will zip resources before sending them back to a browser. That does mean the server has to do a bit more processing, as it needs to compress resources first. However, the overhead is fairly small and the compressed files are much smaller. The content is therefore be delivered faster.

The Optimize Website interface

The Software » Optimize Website interface has has three options for compressing content: it can be disabled, enabled for all content or enabled for specific MIME types. The default option is “Disabled”.

cPanel's 'Optimize Website' interface lets you enabled or disable content compression.
The Optimize Website interface

Before you tweak the setting you should check if compression is already enabled. The Optimize Website option assumes that the server is running Apache, but that is not always the case. Most of our servers run LiteSpeed, which is a drop-in replacement for Apache that comes with many optimisations. One of them is that compression is enabled out of the box. So, if your server runs LiteSpeed you can ignore the Optimize Website option. Changing the setting won’t have any effect. If you are not sure if your website is powered by LiteSpeed, there are different ways to check the server software.

Similarly, many WordPress caching plugins have an option to enable compression. If that is the case for your website then you don’t have to do anything else.

How to check if compression is enabled?

The easiest way to check if compression is enabled is by using one of many online “compression checkers”, such as giftofspeed.com or websiteplanet.com.

Alternatively, you can also use your browser’s developer tools. If you look at the response headers in the first image on this page then you can see that the server is running LiteSpeed. As said, you don’t need to tweak anything if your server is running LiteSpeed. The Optimize Website feature only applies to Apache, so any changes you make are simply be ignored.

And, if you are a command line junkie then you can get the same information via wget:

$ wget -O /dev/null \
--server-response \
--header "Accept-Encoding: gzip,deflate,br" \
example.com
...
  HTTP/1.1 200 OK
  Connection: Keep-Alive
  Keep-Alive: timeout=5, max=100
  content-type: text/html; charset=UTF-8
  link: <http://example.com/wp-json/>; rel="https://api.w.org/"
  transfer-encoding: chunked
  content-encoding: br
  vary: Accept-Encoding
  date: Tue, 19 Oct 2021 10:46:19 GMT
  server: LiteSpeed
...

Compression and MIME types

As mentioned, compressing files does give the server some extra work. It therefore makes sense to only compress files that benefit from compression. Plain text files, such as PHP scripts and CSS and JavaScript files, compress very well. Images and videos do not – those files are already compressed and so there is very little (if any) benefit in compressing them.

This is where the Compress all content and Compress the specified MIME types options come in. If you want, you can specify which file types should be compressed. In practice, though, it is safe to select the Compress all content option.

How cPanel enables compression

The reason is that cPanel always tells Apache to not compress common image files. Below is the directive that is added to the .htaccess file in your home directory when you opt to compress all content:

<IfModule mod_deflate.c>
    SetOutputFilter DEFLATE
    <<fModule mod_setenvif.c>
        # Netscape 4.x has some problems...
        BrowserMatch ^Mozilla/4 gzip-only-text/html

        # Netscape 4.06-4.08 have some more problems
        BrowserMatch ^Mozilla/4\.0[678] no-gzip

        # MSIE masquerades as Netscape, but it is fine
        # BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

        # NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
        # the above regex won't work. You can use the following
        # workaround to get the desired effect:
        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

        # Don't compress images
        SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary
    </IfModule>

    &ltIfModule mod_headers.c>
        # Make sure proxies don't deliver the wrong content
        Header append Vary User-Agent env=!dont-vary
    <<IfModule>
&lt/IfModule>

The main thing to note is the instruction to never compress images towards the bottom:

SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary

The rule matches files with the extensions gif, jpg, jpeg and png. There are many more files you could exclude, such as the newer .webp image format and audio and video files.

As far as I can tell the rule doesn’t include more files because it is ancient. The directive contains a couple of BrowserMatch rules that check if a request comes from Netscape Navigator (or a version of Internet Explorer that tells servers it is Netscape). It is extremely unlikely that anyone visiting your website uses Netscape 4, and Internet Explorer has long since stopped masquerading as Netscape. In fact, chances are you have never heard of Netscape. It was one of the early browsers, and among its claim to fame was that it created JavaScript and the original SSL protocol (which has since been replaced by TLS). Netscape lost the first browser war against Internet Explorer and was effectively abandoned in 2003.

Custom rules

cPanel’s Optimize Website feature is convenient but not optimal. If you prefer you can manually add a directive to your website’s top .htaccess file (you can edit or create a .htaccess file in your home directory). If your Apache server uses mod_deflate (which is highly likely) then you can use a directive like this:

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE image/x-icon
    AddOutputFilterByType DEFLATE image/svg+xml svg svgz
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/x-font
    AddOutputFilterByType DEFLATE application/x-font-truetype
    AddOutputFilterByType DEFLATE application/x-font-ttf
    AddOutputFilterByType DEFLATE application/x-font-otf
    AddOutputFilterByType DEFLATE application/x-font-woff
    AddOutputFilterByType DEFLATE application/x-font-woff2
    AddOutputFilterByType DEFLATE application/x-font-opentype
    AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
    AddOutputFilterByType DEFLATE font/ttf
    AddOutputFilterByType DEFLATE font/otf
    AddOutputFilterByType DEFLATE font/eot
    AddOutputFilterByType DEFLATE font/woff
    AddOutputFilterByType DEFLATE font/woff2
    AddOutputFilterByType DEFLATE font/opentype
</IfModule>

Compression in action

Finally, let’s have a look at how much bandwidth you can save when you use compression. Here, I use wget to download a jQuery file. The first request simply downloads the file, and the second command includes a request header that tells the server that I want a compressed file if possible. I am saving the files as testfile1 and testfile2:

$ wget -O testfile1 \
example.com/jquery-3.6.0.js
--2021-10-19 11:17:42--  http://example.com/jquery-3.6.0.js
Resolving example.com (example.com)... 84.18.195.50
Connecting to example.com (example.com)|84.18.195.50|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 288580 (282K) [application/javascript]
...

$ wget -O testfile2 \
--header="Accept-Encoding: gzip,deflate,br" \
example.com/jquery-3.6.0.js
--2021-10-19 11:18:01--  http://example.com/jquery-3.6.0.js
Resolving example.com (example.com)... 84.18.195.50
Connecting to example.com (example.com)|84.18.195.50|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/javascript]
...

Next, let’s compare the file size. The second file is much smaller than the first:

$ stat -c "%n %s" testfile?
testfile1 288580
testfile2 85119

And if you check the file type you see that the second file contains gzip compressed data rather than plain text:

$ file testfile?
testfile1: ASCII text
testfile2: gzip compressed data, from Unix, original size modulo 2^32 288580

Gzipping minified data

Minified data can also be compressed – it still saves a fair amount of bandwidth. For instance, here I download and check the size of a minified version of the jQuery file:

$ wget -O testfile3 example.com/jquery-3.6.0.min.js
$ wget -O testfile4 --header="Accept-Encoding: gzip,deflate,br" example.com/jquery-3.6.0.min.js

$ stat -c "%n %s" testfile[3-4]
testfile3 89501
testfile4 30902