# Rewrite rule for cache busting URLs

**URL:** <https://www.ruby-forum.com/t/rewrite-rule-for-cache-busting-urls/189903>\
**Category:** NGINX\
**Created:** [June 9, 2010, 5:22pm UTC](https://www.ruby-forum.com/t/rewrite-rule-for-cache-busting-urls/189903 "2010-06-09T17:22:53Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![bkirkbri](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b19c9b/32.png) [@bkirkbri](https://www.ruby-forum.com/u/bkirkbri)\
**Post date:** [June 9, 2010, 5:22pm UTC](https://www.ruby-forum.com/t/rewrite-rule-for-cache-busting-urls/189903/1 "2010-06-09T17:22:53Z")

</div>

Our application uses versioned URLs like  
[http://domain.com/r123456789/resource/uri](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:

```auto
#################################################
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:

> **[Rewrite rule for cache busting URLs](https://forum.nginx.org/read.php?2,96334,96334#msg-96334)**
>
> 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: \[code\]...

---

<div class="post-metadata">

**Author:** ![bkirkbri](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b19c9b/32.png) [@bkirkbri](https://www.ruby-forum.com/u/bkirkbri)\
**Post date:** [June 9, 2010, 5:29pm UTC](https://www.ruby-forum.com/t/rewrite-rule-for-cache-busting-urls/189903/2 "2010-06-09T17:29:19Z")

</div>

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.

> **[Igor Sysoev](http://sysoev.ru/en/)**

---

<div class="post-metadata">

**Author:** ![bkirkbri](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b19c9b/32.png) [@bkirkbri](https://www.ruby-forum.com/u/bkirkbri)\
**Post date:** [June 9, 2010, 6:14pm UTC](https://www.ruby-forum.com/t/rewrite-rule-for-cache-busting-urls/189903/3 "2010-06-09T18:14:24Z")

</div>

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:

```auto
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:

> **[Re: Rewrite rule for cache busting URLs](https://forum.nginx.org/read.php?2,96334,96358#msg-96358)**
>
> 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: \[code\]...

---

<div class="post-metadata">

**Author:** ![bkirkbri](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b19c9b/32.png) [@bkirkbri](https://www.ruby-forum.com/u/bkirkbri)\
**Post date:** [June 9, 2010, 9:57pm UTC](https://www.ruby-forum.com/t/rewrite-rule-for-cache-busting-urls/189903/4 "2010-06-09T21:57:26Z")

</div>

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. 🙂

Thanks again Igor for the advice and the amazing software.

Best,  
Brian

Posted at Nginx Forum:

> **[Re: Rewrite rule for cache busting URLs](https://forum.nginx.org/read.php?2,96334,96441#msg-96441)**
>
> 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: \[code\]...

---

<div class="post-metadata">

**Author:** ![bkirkbri](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b19c9b/32.png) [@bkirkbri](https://www.ruby-forum.com/u/bkirkbri)\
**Post date:** [June 9, 2010, 8:33pm UTC](https://www.ruby-forum.com/t/rewrite-rule-for-cache-busting-urls/189903/5 "2010-06-09T20:33:08Z")

</div>

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.

> **[Igor Sysoev](http://sysoev.ru/en/)**

---

<div class="post-metadata">

**Author:** ![bkirkbri](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b19c9b/32.png) [@bkirkbri](https://www.ruby-forum.com/u/bkirkbri)\
**Post date:** [June 9, 2010, 10:11pm UTC](https://www.ruby-forum.com/t/rewrite-rule-for-cache-busting-urls/189903/6 "2010-06-09T22:11:29Z")

</div>

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. 🙂

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.

> **[Igor Sysoev](http://sysoev.ru/en/)**
