277

How to enable browser caching for my site? Do I just put cache-control:public somewhere up in my header like this?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
Cache-Control:public;
>

I am using the latest version of PHP developing on the latest version of XAMPP.

2
  • what server side language are you using? PHP?, ASP?, JSP? the way you set the headers is similar but not quite the same. Or if you are caching images... often this is done in your Apache (or web server) config
    – scunliffe
    Commented Dec 18, 2010 at 21:51
  • Sadly that "solution" simply generates an invalid DOCTYPE ;-) If you wish to do it from HTML (I wouldn't recommend it), you'd use META HTTP-EQUIV
    – user166390
    Commented Dec 19, 2010 at 3:54

8 Answers 8

239

To use cache-control in HTML, you use the meta tag, e.g.

<meta http-equiv="Cache-control" content="public">

The value in the content field is defined as one of the four values below.

Some information on the Cache-Control header is as follows

HTTP 1.1. Allowed values = PUBLIC | PRIVATE | NO-CACHE | NO-STORE.

Public - may be cached in public shared caches.
Private - may only be cached in private cache.
No-Cache - may not be cached.
No-Store - may be cached but not archived.

The directive CACHE-CONTROL:NO-CACHE indicates cached information should not be used and instead requests should be forwarded to the origin server. This directive has the same semantics as the PRAGMA:NO-CACHE.

Clients SHOULD include both PRAGMA: NO-CACHE and CACHE-CONTROL: NO-CACHE when a no-cache request is sent to a server not known to be HTTP/1.1 compliant. Also see EXPIRES.

Note: It may be better to specify cache commands in HTTP than in META statements, where they can influence more than the browser, but proxies and other intermediaries that may cache information.

6
  • 52
    HTML5 forbids this and <meta> has always been a terrible and flaky way to specify caching.
    – Kornel
    Commented May 2, 2014 at 16:56
  • 3
    @porneL I have trouble understanding which part of your links forbids which part of the answer... the meta tag specs say nothing about disliking what's written here, or forbiding it ? Commented Sep 4, 2014 at 14:35
  • 1
    @FélixGagnon-Grenier "The http-equiv attribute is an enumerated attribute" means it allows only values in the table in the spec. It even calls out caching in the later section ("other pragma directives"): > Pragma directives corresponding to headers that affect the HTTP processing model (e.g. caching) must not be registered, as they would result in HTTP-level behavior being different for user agents that implement HTML than for user agents that do not.
    – Kornel
    Commented Sep 5, 2014 at 14:44
  • 7
    The quoted document is not correct with respect to the no-store value (despite the document itself referencing RFC 2068) - no-store prevents the document being stored/cached at all, anywhere. Whereas no-cache does allow it to be stored, but it must check with the server every time. Browsers will tend to store no-cache pages to enable back button functionality etc.
    – MrWhite
    Commented Apr 1, 2015 at 8:08
  • 5
    Google provides one of the easiest references for HTTP caching IMO: developers.google.com/web/fundamentals/performance/…
    – MrWhite
    Commented Apr 1, 2015 at 8:08
154

You can set the headers in PHP by using:

<?php
  //set headers to NOT cache a page
  header("Cache-Control: no-cache, must-revalidate"); //HTTP 1.1
  header("Pragma: no-cache"); //HTTP 1.0
  header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past

  //or, if you DO want a file to cache, use:
  header("Cache-Control: max-age=2592000"); //30days (60sec * 60min * 24hours * 30days)

?>

Note that the exact headers used will depend on your needs (and if you need to support HTTP 1.0 and/or HTTP 1.1)

3
72

As I wrote is best to use the file .htaccess. However beware of the time you leave the contents in the cache.

Use:

<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>

Where: 604800 = 7 days

PS: This can be used to reset any header

2
  • 8
    If you have access to your webserver configuration, you can put this there instead of in .htaccess. There is a misconception about that you have to put some things in .htaccess in Apache and it keeps getting fed by answers like these. You don't need ANY .htaccess unless you do not have direct acess to webserver config (e.g. in a multi vhost environment). Maybe just write webserver configuration OR .htaccess. See danielmorell.com/guides/htaccess-seo/basics/… Commented Jul 11, 2020 at 15:37
  • 1
    Also you might add that you need mod_headers (or enclose it in an <IfModule). Commented Jul 11, 2020 at 15:37
36

The page at http://www.askapache.com/htaccess/apache-speed-cache-control.html suggests using something like this:

Add Cache-Control Headers

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
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
Header set Cache-Control "max-age=290304000, public"
</FilesMatch>
5
  • 3
    Is order in this important? "max-age=290304000, public" Or "public, max-age=290304000" or both are equally right? Commented Sep 8, 2013 at 8:02
  • 2
    Order does not matter if the values are not conflicting (like cache and no-cache). max-age and public do not conflict so order does not matter.
    – Blaise
    Commented Nov 25, 2014 at 13:50
  • 3
    Note that since it uses the Header directive, you have to enable mod_headers. Commented Jan 25, 2018 at 13:05
  • @Skippy le Grand Gourou how do I enable mod_headers?
    – Sam
    Commented Jul 5, 2018 at 6:56
  • @SamuelStratford I read it differs on other distributions, but under Debian you can either use a2enmod or make a symbolic link from /etc/apache2/mods-available/headers.load to /etc/apache2/mods-enabled/headers.load. Commented Jul 5, 2018 at 14:19
31

This is the best .htaccess I have used in my actual website:

<ifModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
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>

##Tweaks##
Header set X-Frame-Options SAMEORIGIN

## EXPIRES CACHING ##
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 1 month"
</IfModule>
## EXPIRES CACHING ##

<IfModule mod_headers.c>
    Header set Connection keep-alive
    <filesmatch "\.(ico|flv|gif|swf|eot|woff|otf|ttf|svg)$">
        Header set Cache-Control "max-age=2592000, public"
    </filesmatch>
    <filesmatch "\.(jpg|jpeg|png)$">
        Header set Cache-Control "max-age=1209600, public"
    </filesmatch>
    # css and js should use private for proxy caching https://developers.google.com/speed/docs/best-practices/caching#LeverageProxyCaching
    <filesmatch "\.(css)$">
        Header set Cache-Control "max-age=31536000, private"
    </filesmatch>
    <filesmatch "\.(js)$">
        Header set Cache-Control "max-age=1209600, private"
    </filesmatch>
    <filesMatch "\.(x?html?|php)$">
        Header set Cache-Control "max-age=600, private, must-revalidate"
      </filesMatch>
</IfModule>
4
  • 5
    Almost perfect example of a .htaccess file... It would be complete if specific images were included & how to write the path to the image AND where to put the .htaccess file (eg. in image dir or index dir)?...eg. '<IfModule mod_headers.c> <Files /img/myimage.jpg> Header append Cache-Control "max-age=3600, must-revalidate" </Files></IfModule>'... would this work?... OR... or pasted to img dir '<filesmatch "^(example\.jpg|sample\.png)$">Header set Cache-Control "max-age=31536000, public"</filesmatch>'... An all the same strategy seems risky - anyway specific examples would be great if poss Commented Nov 27, 2016 at 20:31
  • 3
    just FYI: gzip compression on JS and CSS files can help to break your SSL encryption. If you rely on security, do not turn gzip on Commented May 17, 2017 at 7:14
  • 2
    This is caching the login account page, so you can't log out from your account. Even worse someone can't just access the account page and be logged in with last users login. It's not advisable to use on an eCommerce site, you should then remove the <filesMatch "\.(x?html?|php)$"> to avoid static HTML pages to be cached. The rest of the filematches are ok.
    – nicoX
    Commented May 25, 2018 at 19:42
  • 2
    You set css and js to private if you have proxy caching. I couldn't find any recommendations in your link regarding that. Most CDN's are recommending you cache those values.
    – nicoX
    Commented May 28, 2018 at 9:11
17

For Apache server, you should check mod_expires for setting Expires and Cache-Control headers.

Alternatively, you can use Header directive to add Cache-Control on your own:

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

The meta cache control tag allows Web publishers to define how pages should be handled by caches. They include directives to declare what should be cacheable, what may be stored by caches, modifications of the expiration mechanism, and revalidation and reload controls.

The allowed values are:

Public - may be cached in public shared caches
Private - may only be cached in private cache
no-Cache - may not be cached
no-Store - may be cached but not archived

Please be careful about case sensitivity. Add the following meta tag in the source of your webpage. The difference in spelling at the end of the tag is either you use " /> = xml or "> = html.

    <meta http-equiv="Cache-control" content="public">
    <meta http-equiv="Cache-control" content="private">
    <meta http-equiv="Cache-control" content="no-cache">
    <meta http-equiv="Cache-control" content="no-store">

Source-> MetaTags

2
  • 1
    correction: no-store should not be cached, no cache is allowed to be cached but must be checked with the server before being reserved - see palizine.plynt.com/issues/2008Jul/cache-control-attributes Commented Jan 2, 2013 at 11:14
  • Cache-Control no-store - no-store is similar to no-cache in that the response cannot be cached and re-used, however there is one important difference. no-store requires the resource to be requested and downloaded from the origin server each time. This is an important feature when dealing with private information.
    – MarcoZen
    Commented Feb 12, 2020 at 0:39
4

OWASP recommends the following,

Whenever possible ensure the cache-control HTTP header is set with no-cache, no-store, must-revalidate, private; and that the pragma HTTP header is set with no-cache.

<IfModule mod_headers.c>
    Header set Cache-Control "private, no-cache, no-store, proxy-revalidate, no-transform"
    Header set Pragma "no-cache"
</IfModule>
2
  • 1
    Can you add a link? Also, doesn't this depend on the type of content? Why always set no-store? Why private? Only makes sense for pages that are private. Commented Jul 11, 2020 at 15:41
  • The Pragma header is really old (HTTP/1.0), so I suspect this is old advice. Commented Sep 28, 2021 at 13:31

Not the answer you're looking for? Browse other questions tagged or ask your own question.