Wednesday, May 20th, 2009...2:01 pm

Setting Static Asset Expires Headers with nginx and Passenger

Jump to Comments

On a recent project I launched, I’m using the combination nginx+passenger for my front end my my Ruby on Rails application.

While trying to boost my YSlow score, I was having a bit of difficulty trying to figure out how to set HTTP expires headers on all the static assets served by my app.

Rails will set an internal time stamp on static assets (images, css files, javascript files, etc…) by appending a integer value onto the end of the asset filename

My original attempt at getting nginx to set an expires header for these assets had me adding the following location block to my nginx config file:

location ~* \.(ico|css|js|gif|jpe?g|png)\?[0-9]+$ {
    expires max;

The regexp I was using was incorrect however as it didn’t take into account that the ?timestamp might not exist in the URI.

Hongli Lai kindly pointed me in the right direction and showed me the proper regexp that he is using.

location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
    expires max;


  • Thanks for this! After hours of trying to figure this out this finally helped me!

  • awesome. glad to help

  • Another big thank you!! This just helped me finally get expire headers working right on

    It’s loading way faster now. Thanks a ton!

  • Your first regular expression doesn’t match anything, as nginx doesn’t include query string (part after the question mark) when matching location.

    I prefer to set Expires *only* for assets with timestamp included, otherwise your users will have problems when you change the contents of a file without changing the name.

    The following directive will cover this case:

    location ~* \.(ico|css|js|gif|jp?g|png) {
    if ($args ~* [0-9]+$) {
    expires max;

  • Adam, my second regexp (the one I am actually using) does the same thing as your example.

  • Hey craig, I think that your regexp doesn’t match “jpeg” file extensions, but (wrongly) “jg”.

  • @eno,

    You are correct. Good eye.

    I’ve gone ahead and updated the regexp in my example.

  • Hey craig, me again :) Hongli Lai’s example does not work (as Adam already pointed out, because the location test does not include the URL arguments in the test against the regex. Adam’s solution seems ok to me. My own setup is a bit different; if interested check it out here×29-my-nginx-config.

  • @eno,

    Interesting. I’m wondering if this isn’t an nginx version issue, because the regexp I use in the example works fine for me on my website.

    But both you and Adam are saying the check against $location doesn’t work, I’m wondering if its because the $location variable changed in nginx.

    what version are you running? I’m running version 0.6.36 on the server in question.

  • Hi,

    How can I set different expire headers within a single location. For example in case of /images, I want the default expire time to be 1 hr except for logo.gif

  • @Himanshu,

    Just update the location regex map pattern to match the paths you want, in this case your /images directory.

    You can also then set a rule specifically for logo.gif

  • How could I change the regexp of you example if I want that only the files contained in the /static directory are cached?

  • @Francesco,

    try something like the following to cache everything in /static

    location ~ ^/static/

© 2019 Craig P Jolicoeur.