Help Docs Performance Website Optimization Improving Website Speed with Apache mod_expires and browser caching

Improving Website Speed with Apache mod_expires and browser caching

Learn to use Apache's mod_expires on cPanel to set browser caching, boosting site speed and reducing server load.

Improving your website’s loading speed is crucial for user experience and SEO. One effective way to achieve this is by leveraging browser caching. This article will guide you through using Apache’s mod_expires module on your cPanel server to control how browsers cache your site’s content, leading to faster load times for repeat visitors and reduced server load.

Understanding browser caching

When a visitor comes to your website, their browser downloads various assets like images, stylesheets (CSS files), and JavaScript files. Browser caching is a process where the browser stores these files locally on the visitor’s computer. When the visitor returns to your site or navigates to another page that uses the same assets, the browser can load these files from its local cache instead of re-downloading them from your server. This results in significantly faster page loads and a better overall experience for your users.

The benefits of browser caching include:

  • Faster loading times: Cached resources load almost instantly.
  • Reduced server load: Fewer requests to your server mean less processing power and bandwidth are used.
  • Improved user satisfaction: Quicker sites lead to happier visitors.

Introducing Apache mod_expires

mod_expires is an Apache module that allows you to set specific instructions for how long web browsers should keep copies of your site’s files. By sending “Expires” and “Cache-Control” headers, you tell the browser whether it should request a file from the server or just use the one it already has stored in its cache.

Most Liquid Web cPanel servers have mod_expires enabled by default. If you encounter issues, you may need to confirm with our support team if it’s active for your specific hosting environment.

Configuring mod_expires directives

You can configure mod_expires directives by adding them to an .htaccess file in your website’s document root directory (usually public_html/ or a specific domain’s folder within it). You can edit or create this file using the File Manager in your cPanel account.

Always back up your .htaccess file before making any changes, as incorrect syntax can make your website inaccessible.

Enabling mod_expires

First, you need to ensure that mod_expires processing is turned on within your .htaccess file. You do this with the ExpiresActive directive:

ExpiresActive On

Setting a default expiration time

The ExpiresDefault directive sets a baseline caching duration for all content types that you don’t specify individually. The syntax allows you to set the expiration based on either the “access” time (when the user requests the file) or the “modification” time (when the file was last changed on the server).

For example, to set a default expiration of one month from the time of access:

ExpiresDefault "access plus 1 month"

You can use various time units:

  • years
  • months
  • weeks
  • days
  • hours
  • minutes
  • seconds

Setting expiration by MIME type

For more granular control, use the ExpiresByType directive. This allows you to set different caching durations for different types of files (MIME types). This is generally recommended as different file types have different update frequencies.

Here are some common examples:

ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"

ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"

ExpiresByType application/pdf "access plus 1 month"

ExpiresByType application/x-font-ttf "access plus 1 year"
ExpiresByType application/x-font-woff "access plus 1 year"
ExpiresByType application/font-woff2 "access plus 1 year"
ExpiresByType application/vnd.ms-fontobject "access plus 1 year"

ExpiresByType text/html "access plus 0 seconds"
ExpiresByType application/xhtml+xml "access plus 0 seconds"

In the example above, images and fonts are set to be cached for one year because they typically don’t change often. CSS and JavaScript files are cached for one month. HTML files (text/html) are often set to “access plus 0 seconds” or a very short duration, especially for dynamic sites, to ensure users always get the freshest content for the page structure itself, while still allowing its components to be cached.

Complete .htaccess example configuration

Here’s a typical mod_expires configuration block that you can adapt and add to your .htaccess file:

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault                                      "access plus 1 month"

  # HTML
  ExpiresByType text/html                             "access plus 0 seconds"
  ExpiresByType application/xhtml+xml                 "access plus 0 seconds"

  # Data
  ExpiresByType text/xml                              "access plus 0 seconds"
  ExpiresByType application/xml                       "access plus 0 seconds"
  ExpiresByType application/json                      "access plus 0 seconds"

  # Feeds
  ExpiresByType application/rss+xml                   "access plus 1 hour"
  ExpiresByType application/atom+xml                  "access plus 1 hour"

  # Favicon (cannot be renamed)
  ExpiresByType image/vnd.microsoft.icon              "access plus 1 week"
  ExpiresByType image/x-icon                          "access plus 1 week"

  # Media: images, video, audio
  ExpiresByType image/gif                             "access plus 1 month"
  ExpiresByType image/jpeg                            "access plus 1 month"
  ExpiresByType image/png                             "access plus 1 month"
  ExpiresByType image/webp                            "access plus 1 month"
  ExpiresByType image/svg+xml                         "access plus 1 month"
  ExpiresByType video/ogg                             "access plus 1 month"
  ExpiresByType audio/ogg                             "access plus 1 month"
  ExpiresByType video/mp4                             "access plus 1 month"
  ExpiresByType video/webm                            "access plus 1 month"

  # CSS and JavaScript
  ExpiresByType text/css                              "access plus 1 year"
  ExpiresByType application/javascript                "access plus 1 year"
  ExpiresByType application/x-javascript              "access plus 1 year"

  # Web fonts
  ExpiresByType application/x-font-ttf                "access plus 1 year"
  ExpiresByType application/x-font-woff               "access plus 1 year"
  ExpiresByType application/font-woff2                "access plus 1 year"
  ExpiresByType application/vnd.ms-fontobject         "access plus 1 year"
  ExpiresByType font/opentype                         "access plus 1 year"
</IfModule>

The <IfModule mod_expires.c> ... </IfModule> wrapper ensures that these rules are only processed if the mod_expires module is active, preventing errors if it’s not.

Testing your mod_expires configuration

After adding or modifying your mod_expires rules, it’s essential to test them to ensure they’re working as expected. You can use online tools or your browser’s developer console. A quick and effective way to check the headers directly is by using the curl command-line tool.

Using curl -I

curl is a versatile tool for transferring data with URLs. The -I option tells curl to fetch only the HTTP headers of a document.

To test, open a terminal or command prompt and run a command like this, replacing yourdomain.com/path/to/asset.jpg with the actual URL of an asset on your site:

curl -I http://yourdomain.com/path/to/asset.jpg

Or for an HTTPS site:

curl -I https://yourdomain.com/path/to/asset.jpg

You will see output similar to this (details may vary):

HTTP/1.1 200 OK
Date: Thu, 29 May 2025 18:30:00 GMT
Server: Apache
Last-Modified: Mon, 12 May 2025 10:00:00 GMT
ETag: "1a2b3c-4d5e-6f7g8h9i0j"
Accept-Ranges: bytes
Content-Length: 19810
Cache-Control: max-age=2592000
Expires: Sat, 28 Jun 2025 18:30:00 GMT
Content-Type: image/jpeg

Look for the following headers in the output:

  • Expires: This header shows the date and time when the content is considered stale. It should match the duration you set.
  • Cache-Control: max-age=...: This directive is often preferred by modern browsers. max-age specifies the number of seconds for which the resource is considered fresh. For example, max-age=2592000 corresponds to 30 days (30 days * 24 hours/day * 60 minutes/hour * 60 seconds/minute).

If you see these headers and the dates/times reflect your settings, mod_expires is working correctly for that asset type.

Important considerations

  • Do not cache aggressively by default: While caching is good, caching HTML files or dynamic content for long periods can prevent users from seeing updates to your site. Set shorter expiration times for frequently updated content.
  • Clearing cache for testing: When testing, make sure to clear your browser’s cache or use a private/incognito Browse mode to ensure you’re fetching fresh copies and not testing already cached versions.
  • Interactions with other caching: Remember that browser caching is one layer. Your site might also use server-side caching (like LiteSpeed Cache or Memcached) or a Content Delivery Network (CDN). Ensure your mod_expires settings complement these other layers.

By thoughtfully configuring mod_expires, you can significantly enhance your website’s performance and provide a smoother experience for your visitors. If you have any questions or need assistance, our support team is always ready to help!

Was this article helpful?