In the first part of this series I described why tuning the performance of your site is something you should do for both philosophical and practical reasons, as well as where to start. That post was by necessity a bit generic. In the second part of this series we'll dive into some of the basic things you can do in Joomla to unlock a decent amount of performance.

Basic system settings

When building a site we get so caught up in the design and functionality that we forget that some very basic and fairly straightforward system settings can have a massive impact on the performance of our sites. A few simple switches in the Global Configuration before delivering the site and a few simple server checks can make all the difference in the world.

Caching

Most of the time spent on the server side of a site has to do with constructing the page that will be displayed to the visitor. Joomla, unlike WordPress, has a built-in caching system. I feel that people don't give it enough credit because they were used to the subpar caching experience in Joomla 1.0 to 2.5. That was 10 to 15 years ago.

Go to your site's Global Configuration and set caching to "ON - Progressive Caching". The progressive caching option is the better form of Joomla built-in caching, making sure that all elements of your page are cached. When a request comes through, the page is stitched together from cached content whenever possible. This can even work towards mitigating some of the performance lost to a pre-built template. It will definitely work towards making your public, non-logged-in pages faster – exactly what is most relevant for your site's search engine ranking.

As to the caching back-end, I've found that file caching on a decent host is similar or better in performance than memcached or Redis. Heresy, I hear you say. And I agree, to an extent. If you have a truly massive or extremely busy site it makes sense to use a dedicated memcached or Redis server. It will be faster. Chances are that if you're reading this you do not, in fact, have this kind of site and you're looking at speeding up a much more pedestrian site. Even my business site falls into the "more pedestrian" category and we're getting a healthy number of dozens of thousands of unique monthly visitors. That should give you a sense of the site scale that would benefit from non-file caching.

HTML compression

If there was a contest for the most-overlooked option in Joomla, Gzip Page Compression would win hands down. If you haven't already done so, go ahead and enable it.

This option makes sure that the HTML content sent by your site to the browser is compressed using the GZip (also called "deflate") algorithm. This reduces the total size of the data transferred to the client substantially. The amount of time saved in data transfer has a significant impact to your site's performance.

JavaScript and CSS compression

Tempted as you may be, do not use your template's or component's feature to send GZipped versions of JavaScript and CSS files, nor should you give into the temptation of using a third party plugin to GZip such files. All these features work by employing a directly web accessible PHP script which is bad for both security and performance of your site. These script rarely perform any kind of access control, usually allowing an attacker to access files they shouldn't be accessing directly. Sometimes even non-static media. Ouch. On the performance front, the minimal amount of time saved by transmitting a smaller file is lost by the time spent by the web server to launch a new PHP thread, read the file, compress it and then start transferring the compressed data to the browser.

I strongly recommend doing this through your web server itself. If you are using Apache you can add the following to your .htaccess file:

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/plain text/xml text/css application/xml application/xhtml+xml application/rss+xml application/javascript application/x-javascript image/svg+xml
</IfModule>

<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_keep_workfiles No
mod_gzip_can_negotiate Yes
mod_gzip_add_header_count Yes
mod_gzip_send_vary Yes
mod_gzip_min_http 1000
mod_gzip_minimum_file_size 300
mod_gzip_maximum_file_size 512000
mod_gzip_maximum_inmem_size 60000
mod_gzip_handle_methods GET
mod_gzip_item_include file \.(html?|txt|css|js|php|pl|xml|rb|py|svg|scgz)$
mod_gzip_item_include mime ^text/plain$
mod_gzip_item_include mime ^text/xml$
mod_gzip_item_include mime ^text/css$
mod_gzip_item_include mime ^application/xml$
mod_gzip_item_include mime ^application/xhtml+xml$
mod_gzip_item_include mime ^application/rss+xml$
mod_gzip_item_include mime ^application/javascript$
mod_gzip_item_include mime ^application/x-javascript$
mod_gzip_item_include mime ^image/svg+xml$
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include handler ^server-status$
mod_gzip_item_include handler ^server-info$
mod_gzip_item_include handler ^application/x-httpd-php
mod_gzip_item_exclude mime ^image/.*
</IfModule>

Your web server is much faster in compressing static media files and it can keep the compressed files cached in memory for speedier delivery next time around.

Static media caching

Reducing the size of the static media with compression is half the battle and matters primarily for first time visitors. When someone comes back to your site it makes sense for their browser to serve static media from the browser's cache, without hitting the network at all. If you're using Apache you can use the following code in your .htaccess file:

<IfModule mod_expires.c>
# Enable expiration control
ExpiresActive On

# CSS and JS expiration:
ExpiresByType text/css "now plus 1 year"
ExpiresByType application/javascript "now plus 1 year"
ExpiresByType application/x-javascript "now plus 1 year"

# Image files expiration: 1 month after request
ExpiresByType image/bmp "now plus 1 year"
ExpiresByType image/gif "now plus 1 year"
ExpiresByType image/jpeg "now plus 1 month"
ExpiresByType image/jp2 "now plus 1 month"
ExpiresByType image/pipeg "now plus 1 month"
ExpiresByType image/png "now plus 1 month"
ExpiresByType image/svg+xml "now plus 1 month"
ExpiresByType image/tiff "now plus 1 month"
ExpiresByType image/vnd.microsoft.icon "now plus 1 month"
ExpiresByType image/x-icon "now plus 1 month"
ExpiresByType image/ico "now plus 1 month"
ExpiresByType image/icon "now plus 1 month"
 ExpiresByType image/webp "now plus 1 month"
ExpiresByType text/ico "now plus 1 month"
ExpiresByType application/ico "now plus 1 month"
ExpiresByType image/vnd.wap.wbmp "now plus 1 month"
ExpiresByType application/vnd.wap.wbxml "now plus 1 month"
ExpiresByType application/smil "now plus 1 month"

# Font files expiration: 1 week after request
ExpiresByType application/vnd.ms-fontobject "now plus 1 week"
ExpiresByType application/x-font-ttf "now plus 1 week"
ExpiresByType application/x-font-opentype "now plus 1 week"
ExpiresByType application/x-font-woff "now plus 1 week"
ExpiresByType font/woff2 "now plus 1 week"
ExpiresByType image/svg+xml "now plus 1 week"

# Audio files expiration: 1 month after request
ExpiresByType audio/ogg "now plus 1 month"
ExpiresByType application/ogg "now plus 1 month"
ExpiresByType audio/basic "now plus 1 month"
ExpiresByType audio/mid "now plus 1 month"
ExpiresByType audio/midi "now plus 1 month"
ExpiresByType audio/mpeg "now plus 1 month"
ExpiresByType audio/mp3 "now plus 1 month"
ExpiresByType audio/x-aiff "now plus 1 month"
ExpiresByType audio/x-mpegurl "now plus 1 month"
ExpiresByType audio/x-pn-realaudio "now plus 1 month"
ExpiresByType audio/x-wav "now plus 1 month"

# Movie files expiration: 1 month after request
ExpiresByType application/x-shockwave-flash "now plus 1 month"
ExpiresByType x-world/x-vrml "now plus 1 month"
ExpiresByType video/x-msvideo "now plus 1 month"
ExpiresByType video/mpeg "now plus 1 month"
ExpiresByType video/mp4 "now plus 1 month"
ExpiresByType video/quicktime "now plus 1 month"
ExpiresByType video/x-la-asf "now plus 1 month"
ExpiresByType video/x-ms-asf "now plus 1 month"
</IfModule>

HTTPS and HSTS

There's a common misconception that HTTPS has something to do with securing your site, it's expensive, it's slow and you don't really need it unless you're doing e-commerce or something. Another misconception is that it makes your site slower.

These myths originated in the late 1990s. Over two decades ago they are patently false.

HTTPS is pretty much mandatory these days. If you don't use HTTPS your site will appear with a red sign stating it's insecure, scaring visitors away. It will be penalized by search engines. You should use HTTPS if only to fix these two problems. You don't even need to break the piggy bank. TLS certificates are now free of charge thanks to Let's Encrypt. Most hosting control panels integrate with Let's Encrypt, meaning that you can literally have your hosting control panel issue and install a free TLS certificate and auto-renew it. There is zero maintenance on your part. HTTPS is also super fast since any modern CPU, released over the past ten-odd years, has hardware acceleration for the cryptographic operations it uses.

While you're at it, remember to set Force HTTPS to Entire Site in your Global Configuration. This ensures that your Joomla site will always be delivered over HTTPS, making logins more secure in the process. Once you do that and you've confirmed HTTPS works great with your site add the following to your .htaccess:

<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000" env=HTTPS
</IfModule>

This enables a feature called HSTS (HTTP Strict Transport Security). In short, it tells your browser to never even try to connect to the HTTP version of your site, regardless of what your visitor tells it to do. Since this happens on the browser side a visitor who types your domain name in the address bar without the https:// prefix, or clicks a link with the http:// prefix, will always get to the HTTPS version of your site without having to first visit the plain HTTP version and get redirected by Joomla. This is much faster, especially on high-latency connections such as mobile or satellite Internet.

A further optimization you can do is submit your site to the HSTS Preload List. While HSTS only works after the first time someone visits your site, having your site in the HSTS Preload List means that the browser knows about your site using HSTS before the first time your visitor visits it. Therefore, the browser will never attempt to load it over plain HTTP. Again, this is a time saver for high-latency connections, easy and free. What's not to love about it?

HTTP/2 Server Push

The ulterior motive for using HTTPS is that it enables us to use HTTP/2. This is a newer version of the HTTP protocol which only works over HTTPS, uses binary headers and supports a few important features that increase the performance of the site.

This is something your host needs to enable on their server. If you are not sure if they do, go to https://http2.pro/ and test the HTTPS version of your site. If it tells you that HTTP/2 is not supported please do contact your host and ask them to enable it.

One of the benefits of HTTP/2 is that it supports server push. Basically, your site can tell the browser "Hey, I noticed you're new here. Here are some CSS, JavaScript and image files you'll definitely need to render this page. You're welcome". By having the server attach the required files to the initial HTML response the browser doesn't have to make separate requests for them. This saves the time for the browser to send a request to the server and wait for the server to process it and start sending data. This is superbly important in two cases. First, when the browser is a long distance away from the server, e.g. the visitor is in the USA but the server is in Frankfurt. The roundtrip time in this case is determined by the speed of light which is a constant in our universe; you can't make it go faster! The other case is when we have high-latency such as mobile or satellite Internet. Even on regular wired connections it can save precious hundreds to thousands of milliseconds.

While Joomla does not have built-in HTTP/2 Server Push support (yet?), you can always use Michael Richy's Server - HTTP/2 Push plugin. Do remember that HTTP/2 Push only happens the first time a visitor requests a resource during the user session. When you are testing it on your site do remember to not just clear your browser's cache but also the cookies sent by your site to reset the session.

To be continued

Come back tomorrow for Part III: Static media optimisation.

12 comments

  • Great article!
    I see that you not gzip font files (if local): are not useful?

    I see that is used mod_deflate and the mod_gzip, is it for backward compatibility?

     

    Thanks!

    • That's an excellent question! I forgot to address that in the article. Whether you need to compress fonts files depends on the font file format.

      SVG fonts are written in a markup (text) format. You will see that the .htaccess code I posted already compresses it through Gzip.

      It makes no sense compressing WOFF / WOFF2 fonts. They are already compressed. WOFF2 fonts are compressed even more efficiently than WOFF fonts. Passing them through Gzip results in no size change, it just wastes server resources.

      EOT and TTF fonts can and should be compressed but there is no point using them anymore. All browsers released this side of 2013 support WOFF fonts. If you are still targeting Internet Explorer 9 or earlier or historic versions of the other major browsers which would require you to use EOT or TTF fonts you should indeed compress these files. I don't have this use case so I didn't bother including EOT and TTF in my .htaccess code. For what it's worth, compressing EOT and TTF fonts with Gzip will bring them down to the same size ballpark as WOFF files.

      TL;DR: Use WOFF or WOFF2 fonts. They are already compressed and supported by all browsers your visitors are likely to use.

  • Hello and thanks for these very detailed and interesting tips!

    I was wondering, can I use admin tools to add the code you indicate to htaccess file? ( in the insert custom code fields? )

    Thansk for your feedback!

      • Hello Nicholas,

        Thanks for your reply!

        Just to be sure, when you admintools does all that, do you mean this htaccess rules are already set, or do you mean that i can add them in the field "insert custom code"?

        Sorry for the noob question, i'd just like to be sure :-)

        BTW: I am a long time customer of Akeeba and use admin tools pro and akeeba backup on all our sites. :-) Your products are amazing!

         

      • Admin Tools Professional's .htaccess Maker can already do all of that without adding custom code. The options you are looking for are:

        • Set a long expiration time for static media
        • Automatically compress static resources
        • HSTS Header (for HTTPS-only sites)

        The actual .htaccess code produced by Admin Tools is a bit more elaborate for two of these options than what I described in this blog post here.

  • Hello Nicholas

    Great article thanks!

    When caching should we also switch the page cache plugin on?

    Are there upsides and downsides to this? e.g. not recommended for shopping carts, and if you update an article do you need to clear the page cache to see the new version?

    Michael

     

    • The page cache plugin tells the browser to cache the page and not look for a new version unless it either expires or you force reload. What will actually happen depends on the browser. I never use it because it does get in the way of AJAX requests which go through Joomla's com_ajax (core Joomla doesn't care to send cache busting headers in com_ajax which is why I do NOT use it in Akeeba Backup and probably never will).

      Regarding cleaning the cache, you needn't do that manually when you are making a change to a Joomla article. Joomla itself will clear the com_content cache. However, if you are not using file cache you will indeed have to clean the cache yourself. Unfortunately, most people maintaining Joomla don't seem capable of trivial tasks such as running Redis or memcached on their local machines to test these simple things...

      PS: I am aware that comments don't show up immediately on my blog because of caching. Apparently, Joomla 4 changed the internals of cache handling in a way that the old code which worked with Joomla 3 doesn't fail with an error, it just does nothing. I've already fixed that in https://github.com/akeeba/fof/commit/14ee1356d6e10188db9fdf63721ebb16174e1502 but haven't gotten around updating my site with this change yet.

  • Thanks for the great series of articles.

    I have one question for HTML and JS/CSS compression. By now I had Gzip enabled in Joomla System Configuration and used JCH Optimize that combined JS/CSS files, minify and compresses them and lazy loads images.

    After reading part 2 of your series, I turned off compression in JCH Optimize, but let it combine, minify and lazy load images. Now compression is done by my web server that is IE 11 with compression libraries for Brotli installed and configured. Perfect: CSS/JS files are Brotli compressed now as seen with Firefox network analysis.

    This is why I disabled Gzip in Joomla System Configuration, since it is all done by IIS now. Firefox network analysis shows all compressable files compressed with Brotli.

    So am I right in this case to disable Gzip in Joomla?

     

    • Hello Klaus,

      IIS has two different settings for automatic content compression: static and dynamic.

      Static content compression will compress static files such as CSS and JavaScript. This you have already done.

      Dynamic content compression allows you to compress the output of dynamic scripts, e.g. PHP. This of course includes Joomla itself. If you have enabled dynamic content compression in IIS you can and should turn off Gzip page compression in Joomla's Global Configuration. 

      I hope this helps!

      • Hi Nicholas,

         

        thank you. I forgot to mention that. Dynamic compression is enabled on ISS. Actually, it was always enabled, but I was not aware of the nonsense,having both enabled. So, I was aware after reading your article. ;-)