FREE THOUGHT · FREE SOFTWARE · FREE WORLD

Home  »  Htaccess  »  Speed Tips: Add Cache-Control Headers

by 40 comments

Cache-Control Headers OnUsing Cache-Control headers you can specify which types of proxies can cache certain content, and how long files should be cached. You can also add the must-revalidate header to force checking the ETag and or Last-Modified for the file to make sure the cache is using the current version.


Add Cache-Control Headers

Keep in mind, if you use a far future Expires header you have to change the component's filename whenever the file changes. So please add must-revalidate to your Cache-Control header for your .html files.

This goes in your root .htaccess file but if you have access to httpd.conf that is better.

This code uses the FilesMatch directive and the Header directive to add Cache-Control Headers to certain files.

# 480 weeks

Header set Cache-Control "max-age=290304000, public"


# 2 DAYS

Header set Cache-Control "max-age=172800, public, must-revalidate"


# 2 HOURS

Header set Cache-Control "max-age=7200, must-revalidate"

If you are using far Future Expires Headers and Cache-Control (recommended), you can do this for these files.


Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"

Without Cache-Control Headers

No Cache-Control Headers

With Cache-Control Headers

Cache-Control Headers On

Currently AskApache.com Uses

You can use the HTTP Header Viewer Tool to check it.

Header unset Pragma
FileETag None
Header unset ETag

# 1 YEAR

Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Last-Modified


# 2 HOURS

Header set Cache-Control "max-age=7200, must-revalidate"


# CACHED FOREVER
# MOD_REWRITE TO RENAME EVERY CHANGE

Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Last-Modified

Tags

March 10th, 2008

Comments Welcome

  • Stasigr

    Hello, very nice site, keep up good job!
    Admin good, very good.

  • Claude Haney

    I had AOL Hosting FTP - Now new to DSN Hosting - got a good HOST - but when I upload a "OVERWRITE" file replacement - it taks at least 4- 6 hours for the replacement file to take hold and show. They say this is cause AOL use 'Proxy Caching Servers' which hold the last known version of a web page. I don't understand the code I need to overcome this caching - I have tried cleaning all caches browser and AOL - but still don't work.

    I'm sure the answer is in the above box - Easy Apache Speed Tips Articles - but don't understand - I know HTML code pretty well and never use an Editor. I'm lost here. Any help would really be appreciated..

    Claude

  • ed neville

    Thanks that's highly useful. Cache headers can be highly useful.

  • computerz

    Hi,

    I 've added cache control in my .htaccess like this.

    #Header set Cache-Control "max-age=290304000, public"

    But by adding it its giving me 500 internal server error as soon as i remove it, it starts working.

    What should be the problem behind this?

    Thanks.

  • http://www.cinemaboard.com styx

    Very good explanation, but I don't know why it don't works for me :( Maybe it's my hosting ...

  • http://www.zimmer101.de/wii-spiele/ Aktuell

    Thanks for these tipps. They helped me a lot! I hope my website is now faster as ever ;-)

  • http://Way2Bliss.com Peter

    Hello,
    I love this website.
    I am trying to implement caching on my site and have .htaccess uploaded to root folder with redirectmatch forwarding of *.html pages to *.php so I know my .htaccess is working.

    But when I implement:

    RedirectMatch permanent ^(.*).htm(l?)$ $1.php
     
    Header set Cache-Control "public"
    Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"

    In my .htaccess I get

    Internal Server Error The server encountered an internal error or misconfiguration and was unable to complete your request.

    Suggestions appreciated as I am stumped.

    Thank you.

  • HotCode

    Very nice post! This (HTTP Cache-Control w .htaccess) is just what I am looking for to add to my server, thanks for sharing!

  • http://www.zehub.com/index.php Samir

    Thanks a lot for this tips. I tried to implement this and it seems working (all previous codes generated 500 error system). I'll see with Google Webmasters Tools if the page speed will be better in 2 weeks ;)

  • Thompson

    Will this interfere with W3 Total cache or other caching plugins? For instance, if I tell the plugin to clear the page cache, will old content still be cached locally by users? What's the best way to make them play nice together?

  • http://www.usmomssite.com Christine

    After many different articles and codes to add to my htaccess this one finally worked! Thank you!

  • http://macem.net macem

    probably your apache not support Header (module) computerz ~ and Peter ~

  • Lucas Arruda

    computerz ~,

    you need heade_module enabled on Apache!

  • http://jodoh.net Jodoh

    Thank you very much, Askapache. Those line very help me and my improved site speed. Your tutorial always nice and smart (I read your site since 2 years ago and use it's tip every where)
    Thank you.

  • http://hoogste-spaarrente.en-ik.com/ hoogste spaarrente

    perfect! thanks,
    was playing around with html meta tags, but this solution is a complete fix for all !
    thank you very much!

  • Richard

    This works, excellent! Thank you!

  • http://macem.net macem

    @computerz~

    problem is with Your hosting, please ask provider to check is apache module 'Header' is working correctly.

  • testohs

    here is what I have:

    1. OHS webserver proxy "/" to app server, but excludes path "/static"
    2. on App server, there are some relatively static files served by app server

    so If url: http://webserver:port/static, it is served from webserver, http://webserver:port/appstatic will be served from app server

    I am trying to set cache-control headers on OHS server for both
    http://webserver:port/static
    and
    http://webserver:port/appstatic

    except FileMatch, can I use or location instead?
    do you have a good suggestion?

  • http://www.lynch.ie Computer Rerpair Dublin

    What about if your using IIS based hosting!?

  • http://byteful.com/blog/ Andärin

    Thanks for this. I had troubling finding some good example code for setting the Cache-Control, but this did the trick. Now my blog and gallery are totally cached! Thanks again!

  • Renato Merino

    Hi:

    First iwant to thank you for all the tricks you have on this amazing website, im starting with pagespeed and i notice that no matter which code i paste in my htaccess i always get the Optimize caching warning: "By specifying a cache validator - a Last-Modified or ETag header - you ensure that the validity of cached resources can efficiently be determined."

    I read your all your related posts and still nothing:

    Header unset Pragma
    FileETag None
    Header unset ETag

    # 1 YEAR

    Header set Cache-Control "public"
    Header set Expires "Mon, 17 Dic 2012 20:00:00 GMT"
    Header unset Last-Modified

    # 4 HOURS

    Header set Cache-Control "max-age=14400, must-revalidate"

    # CACHED FOREVER
    # MOD_REWRITE TO RENAME EVERY CHANGE

    Header set Cache-Control "public"
    Header set Expires "Mon, 17 Dic 2015 20:00:00 GMT"
    Header unset Last-Modified

    Am i doing something wrong or do i need to paste something else?

    Thanks for any help in advance

    • http://www.askapache.com/ AskApache

      Use my online http header tool to view http://www.askapache.com/ to see which headers I send, and which ones your site sends, then find what headers you are missing (probably just need to this):

      Header set Cache-Control "public,max-age=29030400"
  • http://gorillavacationsafari.com/ Philemon

    Informative article, this is the best information so far its easier to follow. Thanks

  • http://www.learn-new-skills-from-home.com ECDL

    Thank you for the advice, hopefully it will push my page speed up :)

  • James

    When I added the following code, I am getting two expiry dates.

    Header set Cache-Control "public"
    Header set Expires "Thu, 31 Dec 2013 20:00:00 GMT"
    Header unset Last-Modified

    Mine is an Elgg installation. Can you suggest some better optimizations for the elgg htaccess?

    # Elgg htaccess directives
    # Copyright Curverider Ltd 2008-2009
    # License http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
    # Link http://elgg.org/
     
    <Files "htaccess_dist">
      order allow,deny
      deny from all
    </Files>
     
    # Don't listing directory
    Options -Indexes
     
    # Follow symbolic links
    Options +FollowSymLinks
     
    # Default handler
    DirectoryIndex index.php
     
    # Turn on expiry
    <IfModule mod_expires.c>
      ExpiresActive On
      ExpiresDefault "access plus 10 years"
    </IfModule>
     
    # php 5, apache 1 and 2
    <IfModule mod_php5.c>
      # limit the maximum memory consumed by the php script to 64 MB
      php_value memory_limit 64M
      # register_globals is deprecated as of PHP 5.3.0 - disable it for security reasons.
      php_value register_globals 0
      # post_max_size is the maximum size of ALL the data that is POST'ed to php at a time (8 MB)
      php_value post_max_size 8388608
      # upload_max_filesize is the maximum size of a single uploaded file (5 MB)
      php_value upload_max_filesize 5242880
      # on development servers, set to 1 to display errors. Set to 0 on production servers.
      php_value display_errors 0
    </IfModule>
     
    # Turn on mod_gzip if available
    <IfModule mod_gzip.c>
      mod_gzip_on yes
      mod_gzip_dechunk yes
      mod_gzip_keep_workfiles No
      mod_gzip_minimum_file_size 1000
      mod_gzip_maximum_file_size 1000000
      mod_gzip_maximum_inmem_size 1000000
      mod_gzip_item_include mime ^text/.*
      mod_gzip_item_include mime ^application/javascript$
      mod_gzip_item_include mime ^application/x-javascript$
      # Exclude old browsers and images since IE has trouble with this
      mod_gzip_item_exclude reqheader "User-Agent: .*Mozilla/4..*["
      mod_gzip_item_exclude mime ^image/.*
    </IfModule>
     
    ## Apache2 deflate support if available
    ##
    ## Important note: mod_headers is required for correct functioning across proxies.
    ##
    <IfModule mod_deflate.c>
      AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/x-javascript
      BrowserMatch ^Mozilla/4 gzip-only-text/html
      BrowserMatch ^Mozilla/4.[0678] no-gzip
      BrowserMatch bMSIE !no-gzip
     
    <IfModule mod_headers.c>
      Header append Vary User-Agent env=!dont-vary
    </IfModule>
     
      # The following is to disable compression for actions. The reason being is that these
      # may offer direct downloads which (since the initial request comes in as text/html and headers
      # get changed in the script) get double compressed and become unusable when downloaded by IE.
      SetEnvIfNoCase Request_URI action/* no-gzip dont-vary
      SetEnvIfNoCase Request_URI actions/* no-gzip dont-vary
     
    </IfModule>
     
    # Configure ETags
    <FilesMatch ".(jpg|jpeg|gif|png|mp3|flv|mov|avi|3pg|html|htm|swf|js|ico)$">
      FileETag MTime Size
    </FilesMatch>
     
    #  Add Proper MIME-Type for Favicon to allow expires to work
    AddType image/vnd.microsoft.icon .ico
     
    <IfModule mod_rewrite.c>
     
    RewriteEngine on
     
    # If Elgg is in a subdirectory on your site, you might need to add a RewriteBase line
    # containing the path from your site root to elgg's root. e.g. If your site is
    # http://example.com/ and Elgg is in http://example.com/sites/elgg/, you might need
    #
    #RewriteBase /sites/elgg/
    #
    # here, only without the # in front.
    #
    # If you're not running Elgg in a subdirectory on your site, but still getting lots
    # of 404 errors beyond the front page, you could instead try:
    #
    #RewriteBase /
     
    # In for backwards compatibility
    RewriteRule ^pg/([A-Za-z0-9_-]+)$ engine/handlers/page_handler.php?handler=$1&%{QUERY_STRING}
    RewriteRule ^pg/([A-Za-z0-9_-]+)/(.*)$ engine/handlers/page_handler.php?handler=$1&page=$2&%{QUERY_STRING}
    RewriteRule ^tag/(.+)/?$ engine/handlers/page_handler.php?handler=search&page=$1
     
    RewriteRule ^action/([A-Za-z0-9_-/]+)$ engine/handlers/action_handler.php?action=$1&%{QUERY_STRING}
     
    RewriteRule ^cache/(.*)$ engine/handlers/cache_handler.php?request=$1&%{QUERY_STRING}
     
    RewriteRule ^services/api/([A-Za-z0-9_-]+)/(.*)$ engine/handlers/service_handler.php?handler=$1&request=$2&%{QUERY_STRING}
     
    RewriteRule ^export/([A-Za-z]+)/([0-9]+)/?$ engine/handlers/export_handler.php?view=$1&guid=$2
    RewriteRule ^export/([A-Za-z]+)/([0-9]+)/([A-Za-z]+)/([A-Za-z0-9_]+)/$ engine/handlers/export_handler.php?view=$1&guid=$2&type=$3&idname=$4
     
    # rule for rewrite module test during install - can be removed after installation
    RewriteRule ^rewrite.php$ install.php
     
    # Everything else that isn't a file gets routed through the page handler
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^([A-Za-z0-9_-.]+)$ engine/handlers/page_handler.php?handler=$1 [QSA]
     
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^([A-Za-z0-9_-]+)/(.*)$ engine/handlers/page_handler.php?handler=$1&page=$2 [QSA]
     
    </IfModule>
  • http://www.wordsmile.com Wilma

    thank you, I have used so many codes. But I always got statement:"internal server error". Finally, it really works!

  • http://www.hacktricks.in Hemant

    How can i implement this in blogger?

  • Eric

    Great stuff! So what's better in your opinion?

    # 1 YEAR
    Header set Cache-Control "public"
    Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
    Header unset Last-Modified

    Vs

    ExpiresActive On
    ExpiresDefault "access plus 10 years"
    ExpiresByType text/html "access plus 1 day"
  • http://URL Kate

    Whenever you include a full, simple, clear code in the posts, especially what you're actually doing, you are doing really well. I have to say "thank you".
    I had a page-loading-slow problem, after trying hours, your posts save my time. It takes minutes to get things done.

  • http://www.espace-musculation.com/ Emy

    Thanks you very much

    What do you think about:

    Header add Cache-Control "max-age=7200"
  • brec

    I just used the Header Viewer Tool on askapache.com; why two Cache-Control headers?

    HTTP/1.1 200 OK
    Date: Tue, 14 May 2013 20:56:32 GMT
    Server: Apache
    Vary: Accept-Encoding,Cookie
    Cache-Control: max-age=3, must-revalidate
    Content-Encoding: gzip
    Node: 198.101.159.98, unknown
    Content-Length: 29197
    X-UA-Compatible: IE=Edge,chrome=1
    X-Frame-Options: SAMEORIGIN
    Cache-Control: max-age=3600, must-revalidate, proxy-revalidate
    Keep-Alive: timeout=4, max=46
    Connection: Keep-Alive
    Content-Type: text/html; charset=UTF-8
    Content-Language: en

    • http://www.askapache.com/ AskApache

      Very nice find brec!

      Basically what was going on was I was setting the 3600 Cache-Control header in httpd.conf, and wp-super-cache was setting the max-age=3 Cache-Control header in .htaccess.. for whatever reason they weren't merging correctly. It took me quite a while to fix it. Thanks!

  • brec

    I just used the Header Viewer Tool on askapache.com; why two Cache-Control headers?

    HTTP/1.1 200 OK
    Date: Tue, 14 May 2013 20:56:32 GMT
    Server: Apache
    Vary: Accept-Encoding,Cookie
    Cache-Control: max-age=3, must-revalidate
    Content-Encoding: gzip
    Node: 198.101.159.98, unknown
    Content-Length: 29197
    X-UA-Compatible: IE=Edge,chrome=1
    X-Frame-Options: SAMEORIGIN
    Cache-Control: max-age=3600, must-revalidate, proxy-revalidate
    Keep-Alive: timeout=4, max=46
    Connection: Keep-Alive
    Content-Type: text/html; charset=UTF-8
    Content-Language: en

    • http://www.askapache.com/ AskApache

      Very nice find brec!

      Basically what was going on was I was setting the 3600 Cache-Control header in httpd.conf, and wp-super-cache was setting the max-age=3 Cache-Control header in .htaccess.. for whatever reason they weren't merging correctly. It took me quite a while to fix it. Thanks!

  • http://www3.sympatico.ca/n.rieck/ neil from canada

    A lot of confusing information exists in the comments section of this article so let me add a few points which I tested as working with Apache/2.0.63 (verified by "inspecting my Apache logs" and "observations with WireShark"). First off, there are two flavors of browser caching which I label "careful" and "ruthless". Most browsers default to "careful" and you need to jump through hoops to force them into "ruthless", if that is what you desire. How is this done? By giving browsers less information for each page component. For example, if your server provides both "expires" and "last modified" information for each page component, the browser will default to "careful" then will ask the server "has the page component changed" even if it was just downloaded one second ago (which results in the server responding with 304 "not modified"). Now if your server is like mine (html files contain mostly static components like corporate logos, a js-based sliding menu, etc.) then you want to tell client browsers to cache most page components for anywhere between a few days to a month. This has an effect of saying to the browsers, "don't bug me for validation tests; just use your cached data until expiry". This frees up the server to handle real requests like first-time visits and AJAX transactions. Here is a stub from my copy of file "httpd.conf"

    #-----------------------------------------------------------------------------------------
    # 2013 Apache Tweak to force browsers to cache more stuff
    #
    # notes:
    # 1) 'Expires' requires mod_expire
    # 2) 'Header' requires mod_header
    # 3) Apache docs indicate that Expires will set the necessary header fields so keep
    # your "header set" directives to a minimum
    # 4) Apache is programmable! Increasing the amount of meta data sent to the browser
    # will increase the likelihood that your browser will do more cached-data validation
    # tests (switching from ruthless caching to careful caching) so always send less
    #-----------------------------------------------------------------------------------------
    ExpiresActive On
    #
    # By default, cache all files for 30 days after (A) access
    #
    ExpiresDefault A2592000
    #
    # 24 cache (note: "YSlow v2" would prefer you set these to at least 72 hours)
    #
    ExpiresByType text/css A86400
    # ExpiresByType text/javascript A86400 # this type is not on our site
    # ExpiresByType text/x-javascript A86400 # this type is not on our site
    ExpiresByType application/javascript A86400
    #
    # Do not cache dynamically (AJAX) generated data
    # You might not need these but I recommend keeping text/html under 4 hours
    # so clients can detect changes in page components like .css or .js etc.)
    # With Apache/2.0.63 (on OpenVMS) this also affects static pages (oops)
    #
    ExpiresByType text/html now
    ExpiresByType text/xml now
    ExpiresByType text/plain now
    #
    # Header set Pragma "public" # only used by IE8 and lower
    Header set Cache-Control "public"
    #
    # sending ETags will disable Ruthless Caching (so don't send them)
    #
    Header unset FileETag
    FileETag none
    #--------------------------------------------------------------------------------------

    Caveat: now you might have a new problem: page components will be stuck in the browser's cache and used without first checking with the server. The only way to get around this problem is to incorporate "file version numbers" or "date-time stamps" in the file name of each page component. So an image-of-the-day file named "iotd.gif" might be changed to "iotd_20131130.gif". This means that html files (on ruthless sites) referencing these changed components should use either "low expires" or "modification times" to force the browser to validate the cached html page (and component names) before reusing them.

  • Denis Golotyuk

    Thanks. Useful tool as well for online cache-control debugging: http://highloadtools.com/cachecontrol

  • Loker Terbaru

    thx tips nya:)
    ---
    @Info Lowongan Terbaru :)


Related Articles


My Online Tools
Popular Articles


Hacking and Hackers

The use of "hacker" to mean "security breaker" is a confusion on the part of the mass media. We hackers refuse to recognize that meaning, and continue using the word to mean someone who loves to program, someone who enjoys playful cleverness, or the combination of the two. See my article, On Hacking.
-- Richard M. Stallman









[hide]

It's very simple - you read the protocol and write the code. -Bill Joy

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 3.0 License, just credit with a link.
This site is not supported or endorsed by The Apache Software Foundation (ASF). All software and documentation produced by The ASF is licensed. "Apache" is a trademark of The ASF. NCSA HTTPd.
UNIX ® is a registered Trademark of The Open Group. POSIX ® is a registered Trademark of The IEEE.

+Askapache | askapache

Site Map | Contact Webmaster | License and Disclaimer | Terms of Service

↑ TOPMain