Result from WebPagetest

mod_expires vs mod_headers

Today something weird happened: I made the occasional performance test for my site (this blog) at WebPagetest1 and I got this disastrous result: 

Result from WebPagetest, complete

OK, the result is not absolutly disastrous, since it is limited to one aspect of the performance. The F rating is about static content and means that it is not cached as it could/should be. However, I used to get B ratings here, sometimes A, sometimes C, depending on the page. But never F.

What happened?

A click on the big, red F revealed that the culprit was a non-existing browser caching (“Leverage browser caching”). This is strange since I explicitly tried to get this right a couple of months ago. And I got a good rating back then. What I’ve written into my .htaccess file at that time was this:

<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 2 weeks"
ExpiresByType image/jpeg "access 2 weeks"
ExpiresByType image/gif "access 2 weeks"
ExpiresByType image/png "access 2 weeks"
ExpiresByType image/svg+xml "access 2 weeks"
ExpiresByType video/mp4 "access 2 weeks"
ExpiresByType video/quicktime "access 2 weeks"
ExpiresByType application/pdf "access 2 weeks"
ExpiresByType application/x-font-woff2 "access 2 weeks"
ExpiresByType application/x-font-woff "access 2 weeks"
ExpiresByType application/font-woff2 "access 2 weeks"
ExpiresByType application/font-woff "access 2 weeks"
ExpiresByType text/css "access 1 weeks"
ExpiresByType application/pdf "access 2 weeks"
ExpiresByType text/x-javascript "access 2 weeks"
ExpiresByType image/x-icon "access 1 month"
ExpiresDefault "access 2 days"

And this used to work.

Now I remembered that two months ago my shared hosting provider did a major rework of the whole server infrastructure. I did a quick test and commented the <IfModule mod_expires.c> and </IfModule> conditionals to see what will happen. And, indeed, I got a plain server error. That means that mod_expires is no longer activated on their Apache server. Thanks for not telling me that!

Some minor research brought to the light that you can accomplish the same by using the mod_headers module, instead of mod_expires. Some additional research taught me that the mod_headers approach may even be better than mod_expires. So I gave the following a try:

<IfModule mod_headers.c>
  <FilesMatch "\.(css|js)$">
    Header append Cache-Control "max-age=172800, must-revalidate"
  <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|svg|mp4|mov|swf|woff|woff2)$">
    Header set Cache-Control "max-age=1209600, must-revalidate"

And, voilà, it worked like a charme. Back to my B rating again 🙂 2

What did I learn from that? Check your site’s configuration more often than two times a year. Especially if your hosting provider is not the verbose type!


  1. A highly recommendable site. Much more detailed than Google’s PageSpeedInsights.
  2. I’m using append for css and js because I’m using the Autoptimize plugin (for WordPress), which has its own .htaccess in its directory, and I don’t want to overwrite this. ATM I’m not sure though if this is the best solution. merge doesn’t seem to work due to the Apache version on the server.