Monday, June 4, 2012

Website image caching with Apache

How can I get static content on Apache to be {cached by browser} and not {checked for freshness {with every request}}?

I'm working on a website hosted on Apache webserver. Recently, I was testing something with headers (Content-Type for different types of content) and saw a lot of conditional requests for images. Example:

200 /index.php?page=1234&action=list
304 /favicon.ico
304 /img/logo.png
304 /img/arrow.png

Although the image files are static content and are cached by the browser, every time an user opens a page that links to them, they are conditionally requested, to which they send "304 Not Modified". That's good (less data transferred), but it means 20+ more requests with every page load (longer page load due to all those round-trips, even with Keep-Alive and pipelining enabled).

How do I tell the browser to keep the existing file and not check for newer version?

EDIT: the mod_expires method works, even with the favicon.

Source: Tips4all


  1. I'm experimenting with mod_expires in Apache, loading in and using it in .htaccess.

    With an Expires header, the resource is only requested the first time. Before it hits the expiration date, subsequent requests are fulfilled from cache. After the specified time expires and the resource is needed, it is requested
    again. The only reliable way to clear it from the cache before it expires is manually, or by forcing a refresh (Ctrl-F5). (This could be an issue if it changes in the meantime, but statical images don't change very often.)

    For favicon.ico, a bit more work is needed (Apache normally sends this as text/plain).

    ExpiresActive on
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType image/gif "access plus 1 month"
    ExpiresByType image/jpeg "access plus 1 month"
    # css may change a bit sometimes
    ExpiresByType text/css "access plus 1 days"

    # special MIME type for icons - see
    AddType image/ .ico
    # now we have icon MIME type, we can use it
    # my favicon doesn't change much
    ExpiresByType image/ "access plus 3 months"

    And voila, It Works™!

  2. If you set the Expires header on your http response for your static images, your server won't be checked again for that image after first download until the time specified has passed, e.g. if I download a file from your server now that gives it's Expires header as

    Expires: Fri, 1 Jan 2010 00:00:01 GMT

    then my browser won't look for it from your server again until 2010, unless I clear my cache/do a force refresh (Ctrl+F5 on windows).

    There's a simple introduction to setting this up here, and a list of other possibly helpful responses over at wikipedia

  3. Regarding favicon.ico, put it in your server document root say /var/www/html and add this to /etc/httpd/conf/httpd.conf in the Aliases section:-

    Alias /favicon.ico "/var/www/html/favicon.ico"
    <Directory "/var/www/html">
    <Files favicon.ico>
    ExpiresActive On
    ExpiresDefault "access plus 1 month"

    Then a single favicon.ico will work for all the virtual hosted sites since you are aliasing it. After a user visits your site, any further visits will draw on the browser cache copy for one month, and not from the web.

    I Could not get

    ExpiresByType image/ico "access plus 1 month"

    to work at all. Maybe it needs to be type text/plain as suggested above. In any case ExpiresDefault works OK.

  4. I would use filesMatch directive instead of ExpiresByType, in this way you won't have to bang your head against the type/encoding (i.e. image/jpeg image/ ...)

    #Set caching on image files for 11 months
    <filesMatch "\.(ico|gif|jpg|png)$">
    ExpiresActive On
    ExpiresDefault "access plus 11 month"
    Header append Cache-Control "public"

    Acoording to this Google article I made expiration not longer than 1 year (access plus 11 month) and added Cache-Control "public" to enable HTTPS caching for Firefox.