Rewrite rule for cache busting URLs

Our application uses versioned URLs like
http://domain.com/r123456789/resource/uri to allow for aggressive
caching and easy cache invalidation.

To get this working in nginx, I currently have a config like this:

#################################################
set $cache_control '';

location ~ ^/r\d+/ {
    set $cache_control 'public, max-age=2592000'; # 30 days
    rewrite ^/r\d+(/.*)$ $1 last;
}

location /some/resources {
    if ( $cache_control ) {
        add_header Cache-Control $cache_control;
    }
    alias /path/to/resources;
}

location /some/other/resource {
    if ( $cache_control ) {
        add_header Cache-Control $cache_control;
    }
    alias /some/other/path;
}
#################################################

Is this a bad idea? Likely to fail in the future? Anyone know a better
way?

Could the HTTP Headers module be improved to allow “expires” or
“add_header” to be used inside an “if” condition?

Thanks in advance!

Best,
Brian

Posted at Nginx Forum:

On Wed, Jun 09, 2010 at 11:21:47AM -0400, bkirkbri wrote:

rewrite ^/r\d+(/.*)$ $1 last;
if ( $cache_control ) {
    add_header Cache-Control $cache_control;
}
alias /some/other/path;

}
#################################################
[/code]

Is this a bad idea? Likely to fail in the future? Anyone know a better way?

Could the HTTP Headers module be improved to allow “expires” or “add_header” to be used inside an “if” condition?

Yes, there is a better way:

location ~ ^/r\d+(/some/resources/.+)$ {
alias /path/to/resources/$1;
add_header Cache-Control ‘public, max-age=2592000’; # 30 days
}

location ~ ^/r\d+(/some/other/resources/.+)$ {
alias /some/other/resources/$1;
add_header Cache-Control ‘public, max-age=2592000’; # 30 days
}


Igor S.
http://sysoev.ru/en/

Thanks Igor!

I should have been more specific though. Sometimes the same resource is
referenced in a versioned and non-versioned form. Also, the
versioning applies to many resource locations.

So we would need many config entry pairs like this:

location ~ ^/r\d+(/some/resources/.+)$ {
    alias /path/to/resources/$1;
    add_header Cache-Control 'public, max-age=2592000'; # 30 days
}

location ^~ /some/resources {
    alias /path/to/resources;
}

...

We can do that, but it makes the config harder to maintain.

Another related question: if we configure FastCGI access to our
application in a separate file and include that same config file in many
location {} blocks with “include” will that cause any problems?

Thanks again!

Posted at Nginx Forum:

I understand perfectly. Being clever with lots of rewrites and regexs
does make the config shorter but we have been bitten in the past by
unintended side-effects of all that rewrite chaining (in Apache).

I’ll go with the verbose config with lots of comments then. :slight_smile:

Thanks again Igor for the advice and the amazing software.

Best,
Brian

Posted at Nginx Forum:

On Wed, Jun 09, 2010 at 12:13:22PM -0400, bkirkbri wrote:

}

location ^~ /some/resources {
alias /path/to/resources;
}


[/code]

We can do that, but it makes the config harder to maintain.

People usually think that if they will “rewrite” to pass a processing
in one common location, it makes a configuration easier to maintain.
And if they will make many location given by literal strings (not
regexs),
it makes a configuration harder to maintain.

They are wrong. The maintaince is divided to

  1. changing configuration,
  2. adding functionality.

If you will make many literal locations, the adding is easy: you just
add location in ANY place and you do not need to look how they affect
to old locations. If you need to change configuration you need just
to find/replace relevant things in your favourite editor.
You do not need to look and understand whole configuration.
You need just to be attentive. That’s all.

If you use regex locations or even worse, rewrite’s, then the adding
becames nightmare: you have to look through all configuration to see
how the addintion will affect to previuos configuration.
As to the changing, it may be easy or may be the same nightmare.

Another related question: if we configure FastCGI access to our application in a separate file and include that same config file in many location {} blocks with “include” will that cause any problems?

No, however, it’s better to configure FastCGI in this way:

   location /dir1/ {
       fastcgi_pass   backend;
       fastcgi_param  SCRIPT_FILENAME 

/path/to/$fastcgi_script_filename;
fastcgi_param QUERY_STRING $query_string;
include fastcgi_common;
}

   location /dir2/ {
       fastcgi_pass   backend;
       fastcgi_param  SCRIPT_FILENAME 

/path/to/$fastcgi_script_filename;
fastcgi_param QUERY_STRING $query_string;
include fastcgi_common;
}

   location /dir3/ {
       fastcgi_pass   backend;
       fastcgi_param  SCRIPT_FILENAME  /path/to/index.php;
       fastcgi_param  QUERY_STRING     q=$uri;
       include        fastcgi_common;
   }

Because SCRIPT_FILENAME and QUERY_STRING usually defines how location
should be processed.


Igor S.
http://sysoev.ru/en/

On Wed, Jun 09, 2010 at 03:56:36PM -0400, bkirkbri wrote:

I understand perfectly. Being clever with lots of rewrites and regexs does make the config shorter but we have been bitten in the past by unintended side-effects of all that rewrite chaining (in Apache).

You want to keep making the same mistake. nginx allows to make easily
maintainable configuration. Just forget about rewrites. You should
think how to map URI to file system, but not how to rewrite it.

I’ll go with the verbose config with lots of comments then. :slight_smile:

If I were you, I would place all “/r\d+” regexs inside literal “/r”
location without any comments:

location /r {

location ~ ^/r\d+(/some/resources/.+)$ {
    alias /path/to/resources/$1;
    add_header Cache-Control 'public, max-age=2592000'; # 30 days
}

location ~ ^/r\d+(/some/other/resources/.+)$ {
    alias /path/to/resources/$1;
    add_header Cache-Control 'public, max-age=2592000'; # 30 days
}

...

return 404;

}

location /some/resources {
alias /path/to/resources;
}

This allows to minimize maintaince issues.


Igor S.
http://sysoev.ru/en/