How to add Leverage browser caching for CDN in .htaccess?

If you want to use Leverage browser caching for CDN, it's good to cache files by adding some caching headers like Cache-Control, Expires and Last-Modified.

Leverage Browser Caching using Mod_Headers

If you're on a shared server and your hosts won't enable Mod_Expires, you can still leverage browser caching by using Mod_headers, which will be available.

# Leverage browser caching using mod_headers #
<IfModule mod_headers.c>
    <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
        Header set Expires "Wed, 15 Apr 2020 20:00:00 GMT"
        Header set Cache-Control "public"
    </FilesMatch>
</IfModule>
# End of Leverage browser caching using mod_headers #

below example for testing:

# 1 YEAR
<FilesMatch "\.(flv|ico|pdf|avi|mov|ppt|doc|mp3|wmv|wav)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>

# 1 WEEK
<FilesMatch "\.(jpg|jpeg|png|gif|swf)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>

# 3 HOUR
<FilesMatch "\.(txt|xml|js|css)$">
Header set Cache-Control "max-age=10800"
</FilesMatch>

# NEVER CACHE - notice the extra directives
<FilesMatch "\.(html|htm|php|cgi|pl)$">
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
</FilesMatch>

Testing The Headers

You can verify if the Cache-Control: max-age header is in place on your files by running a “curl” command like:

curl -I http://foo.bar.netdna-cdn.com/file.ext

HTTP/1.1 200 OK
Date: Fri, 16 Sep 2014 14:12:20 GMT
Content-Type: text/css
Connection: keep-alive
Cache-Control: max-age=604800, public  ← 1 Week caching time 
Expires: Thu, 21 May 2015 20:00:00 GMT
Vary: Accept-Encoding
Last-Modified: Thu, 24 Jan 2013 20:00:00 GMT
GMT; path=/; domain=.domain.com
Server: NetDNA-cache/2.2
X-Cache: HIT

you have used below code:

Browser Caching using Mod_Expires
The most common way to leverage browser caching is to use mod_expires. The following code can be added to your .htaccess and will automatically enable browser caching for all users.

# Leverage browser caching using mod_expires #
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/pdf "access plus 1 month"
    ExpiresByType text/x-javascript "access plus 1 month"
    ExpiresByType application/x-shockwave-flash "access plus 1 month"
    ExpiresByType image/x-icon "access plus 1 year"
    ExpiresDefault "access plus 2 days"
</IfModule>
# End of Leverage browser caching using mod_expires #

Probably, it's not the best idea to cache CDN files on your host. If you can leverage on you CDN host than it's better to cache files there by adding some caching headers like Cache-Control, Expires, Last-Modified and so on.

It's better because you just add cache headers to one place - your CDN, instead of adding caching rules to every site that uses your CDN.


What is Browser Caching?

Browser caching is the process of storing previously requested files within your browser’s local cache in order to help reduce loading times. Once a file has been stored locally, fewer requests are required to be sent to the server and less data is required to download.

enter image description here

There are certain components that must be enabled in order to properly leverage browser caching. For instance, you must ensure that you specify a cache validator to help the browser determine if the file can still be retrieved from the local cache or if a request must be made to the server. Additionally, you must properly set Expires or Cache-Control headers for your assets. Using both would be redundant. Furthermore, Gtmetrix prefers Expires over Cache-Control as it is more widely supported. Therefore this article will focus on using Expires headers when demonstrating how to leverage browser caching.

Cache-Control
Cache-Control allows us to have a bit more control of our browser caching and many people find it easier to use once setup.

# 1 Year for most static assets
<filesMatch ".(css|jpg|jpeg|png|gif|js|ico)$">
Header set Cache-Control "max-age=31536000, public"
</filesMatch>

Gzip Comporession(Vary Useful For Magento)

<ifModule mod_gzip.c>
    mod_gzip_on Yes
    mod_gzip_dechunk Yes
    mod_gzip_item_include file \.(html?|txt|css|js|php|pl|asp|html)$
    mod_gzip_item_include handler ^cgi-script$
    mod_gzip_item_include mime ^text/.*
    mod_gzip_item_include mime ^application/x-javascript.*
    mod_gzip_item_exclude mime ^image/.*
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</ifModule>

<ifmodule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript
</ifmodule>

Depending on your website's files you can set different expiry times.
If certain types of files are updated more frequently, you would set an earlier expiry time on them (ie. CSS files).

Open your .htaccess file. (be smart: make a copy of your original .htaccess file, in case you accidentally make a mistake and need to revert).

Now it’s time to enable the Expires headers module in Apache (set the ‘ExpiresActive’ to ‘On’), so add this to your .htaccess file:

<IfModule mod_expires.c>

# Enable expirations
ExpiresActive On 

</IfModule>

It might be useful to add a “Default directive” for a default expiry date, so that’s the 2 rows you’ll add now:

<IfModule mod_expires.c>

# Enable expirations
ExpiresActive On 

# Default directive
ExpiresDefault "access plus 1 month"

</IfModule>

That’s the base. Now add all the lines for each of your file types (you know, the ones you created earlier for your favicon, images, CSS and Javascript). You’ll end up with a code snippet that looks something like this:

<IfModule mod_expires.c>

# Enable expirations
ExpiresActive On

# Default directive
ExpiresDefault "access plus 1 month"

# My favicon
ExpiresByType image/x-icon "access plus 1 year”

# Images
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"

# CSS
ExpiresByType text/css "access 1 month”

# Javascript
ExpiresByType application/javascript "access plus 1 year"

</IfModule>

Now run another test with GTmetrix and compare the results. This is the result for my test site, after implementing Expires headers:

Recommendations

  • Be aggressive with your caching for all static resources
  • Expiry at a minimum of one month (recommended: access plus 1 year)
  • Don't set your caching more than a year in advance!

Browser Caching using WordPress Plugin

W3 Total Cache: One of the best caching plugin with many features like caching, CDN integration (like MaxCDN) that will speed up your website performance.

Note

  1. Make sure that mod_rewrite is enabled on your Apache web server, if not then contact your web server technical team to get it enabled as rewrite module will be needed for completing caching action .
  2. Warning! If you set a far future expiry date for something and then update one of those files, you must change the name of the file for the browser to re-fetch it.
    Example: if you set your javascript to 1 year, and you update one of your javascript files, you’d have to rename the actual file. A good way to do this is by versioning, i.e. myfile_v1.2.js, but the easier way is to be careful with your Expires headers (setting something to 10 years is never a good option IMO).

Did you notice any improvements for your site? Did the above take care of all your files listed under “Leverage browser caching” and “Add Expires headers“? Let me know in the comments below.