Add expiry headers using Apache for paths which don't exist in the filesystem
Asked Answered
E

3

6

For the purposes of CDN invalidation I need to add a prefix to the path element of a site's URL. This is changed whenever a new version of the asset is released.

The URL is then rewritten using mod_rewrite from: http://example.com/cdn/20111030/images/image.jpg to http://example.com/images/image.jpg which is where the asset actually resides.

I would like to add long expiry headers (at least 3 months) to the response (for the first URL which doesn't actually exist in the filesystem). Does anyone know how to do this?

Etienne answered 30/10, 2011 at 21:21 Comment(2)
What do you have so far?Charmeuse
I had: pastebin.com/efc0UCD6Etienne
A
4

From http://drupal.org/node/974350#comment-5305368
These rules are for 480 weeks but you can adjust the time accordingly.

<IfModule mod_rewrite.c>
  RewriteEngine on
  <IfModule mod_headers.c>
    # Transform /cdn/***/ to /
    RewriteCond %{REQUEST_URI} ^/cdn/([0-9a-zA-Z])*/(.+)$
    RewriteRule .* /%2 [L,E=CDN:1]
    # Apache will change CDN to REDIRECT_CDN.

    # Set a far future Cache-Control header (480 weeks), which prevents
    # intermediate caches from transforming the data and allows any
    # intermediate cache to cache it, since it's marked as a public resource.
    Header set Cache-Control "max-age=290304000, no-transform, public" env=REDIRECT_CDN

    # Set a far future Expires header. The maximum UNIX timestamp is somewhere
    # in 2038. Set it to a date in 2037, just to be safe.
    Header set Expires "Tue, 20 Jan 2037 04:20:42 GMT" env=REDIRECT_CDN

    # Pretend the file was last modified a long time ago in the past, this will
    # prevent browsers that don't support Cache-Control nor Expires headers to
    # still request a new version too soon (these browsers calculate a
    # heuristic to determine when to request a new version, based on the last
    # time the resource has been modified).
    # Also see http://code.google.com/speed/page-speed/docs/caching.html.
    Header set Last-Modified "Wed, 20 Jan 1988 04:20:42 GMT" env=REDIRECT_CDN

    # Do not use etags for cache validation.
    Header unset ETag env=REDIRECT_CDN
  </IfModule>
</IfModule>

Also see the AdvAgg rules as these handle servers that do not have mod_headers or mod_expires installed. It uses a FilesMatch directive; advagg files have a fairly unique filename, thus I can do this. The AdvAgg fallbacks wont work in this case because mod_expires can't use environmental variables; neither can FileETag. From what I can see, mod_headers is the desired way to set far future times in apache.

Alialia answered 1/12, 2011 at 11:13 Comment(1)
Thanks, this works great. On Apache 2.2 CDN is not getting changed to REDIRECT_CDN for me so I had to change REDIRECT_CDN to CDN.Slingshot
B
5

It appears that if you add the RewriteEngine/Rule in the Apache configuration for your own solution, the Location is picked up correctly and serves the Expires/Cache-Control on /cdn calls and doesn't serve them for non-cdn calls, with a minor changee:

    # in apache config
    RewriteEngine On
    RewriteRule ^/cdn/[^/]*/(.*) /$1 [L]

    <Location "/cdn">
      Header unset ETag
      FileETag None
      ExpiresActive on
      ExpiresDefault "access plus 1 year"
    </Location>

I can't see a reason this should be a problem in the Apache config.

Biddie answered 5/11, 2011 at 14:5 Comment(4)
The problem with this is that <Location> is not useable in .htaccess, which is where the rest of the mod_rewrite rules are. And if you leave the RewriteRule in .htaccess, by the time the request makes it to the <Location> in the Vhost, for example, the /cdn prefix has already been removed.Etienne
Why can't both be in the apache configuration? That solves the issue.Biddie
You can have RewriteRules in both the apache configuration and .htaccess at the same time, and they wont conflict unless you tell them to.Biddie
Using something almost identical on our project now. Appears to work correctly.Biddie
A
4

From http://drupal.org/node/974350#comment-5305368
These rules are for 480 weeks but you can adjust the time accordingly.

<IfModule mod_rewrite.c>
  RewriteEngine on
  <IfModule mod_headers.c>
    # Transform /cdn/***/ to /
    RewriteCond %{REQUEST_URI} ^/cdn/([0-9a-zA-Z])*/(.+)$
    RewriteRule .* /%2 [L,E=CDN:1]
    # Apache will change CDN to REDIRECT_CDN.

    # Set a far future Cache-Control header (480 weeks), which prevents
    # intermediate caches from transforming the data and allows any
    # intermediate cache to cache it, since it's marked as a public resource.
    Header set Cache-Control "max-age=290304000, no-transform, public" env=REDIRECT_CDN

    # Set a far future Expires header. The maximum UNIX timestamp is somewhere
    # in 2038. Set it to a date in 2037, just to be safe.
    Header set Expires "Tue, 20 Jan 2037 04:20:42 GMT" env=REDIRECT_CDN

    # Pretend the file was last modified a long time ago in the past, this will
    # prevent browsers that don't support Cache-Control nor Expires headers to
    # still request a new version too soon (these browsers calculate a
    # heuristic to determine when to request a new version, based on the last
    # time the resource has been modified).
    # Also see http://code.google.com/speed/page-speed/docs/caching.html.
    Header set Last-Modified "Wed, 20 Jan 1988 04:20:42 GMT" env=REDIRECT_CDN

    # Do not use etags for cache validation.
    Header unset ETag env=REDIRECT_CDN
  </IfModule>
</IfModule>

Also see the AdvAgg rules as these handle servers that do not have mod_headers or mod_expires installed. It uses a FilesMatch directive; advagg files have a fairly unique filename, thus I can do this. The AdvAgg fallbacks wont work in this case because mod_expires can't use environmental variables; neither can FileETag. From what I can see, mod_headers is the desired way to set far future times in apache.

Alialia answered 1/12, 2011 at 11:13 Comment(1)
Thanks, this works great. On Apache 2.2 CDN is not getting changed to REDIRECT_CDN for me so I had to change REDIRECT_CDN to CDN.Slingshot
B
0

A solution could be to apply the Expires to all assets, the use mod_headers to remove the headers from the non-cdn version, e.g.:

 RewriteEngine on
 RewriteRule ^cdn/([0-9a-z])*/(.*) /$2 [L,E=cdn:1]

 ExpiresActive on
 ExpiresDefault "access plus 1 year"
 Header unset Expires env=!cdn
 Header unset Cache-Control env=!cdn

It's a bit overkill for the root of the website, but if only applied to the assets, would be less of an issue.

Biddie answered 1/11, 2011 at 23:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.