Website image caching with Apache

65,652

Solution 1

Expires module in Apache solves this

a2enmod expires

it needs to be loaded in server config, and set up in .htaccess (or in server config).

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

# enable the directives - assuming they're not enabled globally
ExpiresActive on

# send an Expires: header for each of these mimetypes (as defined by server)
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, so define shorter expiration
ExpiresByType text/css "access plus 1 days"

For favicon.ico, a bit more work is needed (Apache normally does not recognize Windows icon files, and sends this as the default text/plain).

# special MIME type for icons - see http://www.iana.org/assignments/media-types/image/vnd.microsoft.icon
AddType image/vnd.microsoft.icon .ico
# now we have icon MIME type, we can use it
# my favicon doesn't change much
ExpiresByType image/vnd.microsoft.icon "access plus 3 months"

And voila, It Works™!

Solution 2

With the filesMatch directive, instead of ExpiresByType, you can group Content-Type by matching subtype (e.g. image/*), instead of listing each type/subtype pair, not subtype (e.g image/jpeg, image/png).

#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"
</filesMatch>

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.

For CSS and JS, Google recommends an expiry period of 1 week.

<filesMatch "\.(css|js)$">
  ExpiresActive On
  ExpiresDefault "access plus 1 week"
  Header append Cache-Control "public"
</filesMatch>

Solution 3

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

Solution 4

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"
    </Files>
</Directory>

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.

Share:
65,652

Related videos on Youtube

Piskvor left the building
Author by

Piskvor left the building

The network has come full circle, and became its own antithesis: from an indispensable fount of knowledge to a dystopian wasteland, with only one rule: ALL ANIMALS ARE EQUAL / BUT SOME ANIMALS ARE MORE EQUAL THAN OTHERS. This is no longer an environment I wish to associate with. https://meta.stackexchange.com/questions/333965/firing-mods-and-forced-relicensing-is-stack-exchange-still-interested-in-cooper

Updated on July 09, 2020

Comments

  • Piskvor left the building
    Piskvor left the building almost 4 years

    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
    (etc.)
    

    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.

  • Tom
    Tom over 14 years
    I have specified my favicon to have a MIME type of "image/x-icon" - and I can't seem to get Apache to set Expires headers on it. Any idea why this is? do i NEED to use image/vnd.microsoft.icon ?
  • Piskvor left the building
    Piskvor left the building over 14 years
    @Tom: "The official IANA-registered MIME type for .ICO files is image/vnd.microsoft.icon." (Wikipedia) So, you don't NEED to use it, but it's the correct MIME type - would you send "image/x-jpg" with JPEG images instead of the standard "image/jpeg"? Is there a technical reason you don't want to return the correct MIME type?
  • Piskvor left the building
    Piskvor left the building over 14 years
    @Tom: as to the first question, the server shouldn't care what the MIME type is, as long as it knows about it. Do you have AddType before ExpiresByType for this MIME type?
  • Tom
    Tom over 14 years
    Cache headers seem set ok on the .ico now - I guess I must have not cleared my browser cache properly when checking the setting after restarting Apache. I'm using ExpiresDefault rather than ExpiresByType. I have started using MIME type of image/vnd.microsoft.icon - thanks for the info. Seemed a bit vendor specific at first but thanks for letting me know about the wikipedia article.
  • Piskvor left the building
    Piskvor left the building almost 13 years
    Good point about the global favicon, if you don't mind that all the sites will share the same one. See my answer re image/ico: 1) image/ico is not the correct MIME type, 2) you need to define image/vnd.microsoft.icon - it is not predefined by Apache.
  • huangli
    huangli over 12 years
    also check http: the definitive guide chapter 7, 7.83 Server Revalidation. book link amazon.com/HTTP-Definitive-Guide-David-Gourley/dp/1565925092
  • Bluebaron
    Bluebaron almost 11 years
    If you need to break the cache just for a specific image, add a ?unique_id to the end of the image request like mylittlepony.png?25130970942
  • Piskvor left the building
    Piskvor left the building almost 11 years
    @Bluebaron: Fair point; however, that requires special handling for each and every instance where you link to that file; and it doesn't solve the issue of outside links. The mod_expires method happens transparently to the page, as a part of HTTP content negotiation.
  • KyleFarris
    KyleFarris almost 10 years
    I like this answer a lot. Thanks for sharing!
  • Rantiev
    Rantiev almost 7 years
    If i need to have '<IfModule mod_headers.c>' check is it all right to have nested directive?
  • rubo77
    rubo77 almost 5 years
    It seems like in Firefox, this header has no effect any more (after 10 years ;) )
  • Piskvor left the building
    Piskvor left the building almost 5 years
    Improbable. Citation-needed;)