# The location directive

**URL:** <https://www.ruby-forum.com/t/the-location-directive/205511>\
**Category:** NGINX\
**Created:** [April 7, 2011, 8:47pm UTC](https://www.ruby-forum.com/t/the-location-directive/205511 "2011-04-07T20:47:55Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dubstep](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/cdc98d/32.png) [@dubstep](https://www.ruby-forum.com/u/dubstep)\
**Post date:** [April 7, 2011, 8:47pm UTC](https://www.ruby-forum.com/t/the-location-directive/205511/1 "2011-04-07T20:47:55Z")

</div>

Hello list

I am new to nginx. I put it into production a couple of weeks ago, and I  
have been very pleased with its efficiency and stability. But I have  
been wondering about an aspect of the location directive. The only  
previous  
discussion I have found of this went dead without resolution (  
[http://forum.nginx.org/read.php?2,4225](http://forum.nginx.org/read.php?2,4225))

By way of illustration, this motif was my first attempt at a  
configuration,  
and I suspect – assuming I am not unusually dense – that others coming  
from Apache will have tried it too:

server {  
listen 80;  
root /www/;

location ~ .php$ {  
fastcgi\_pass unix:php.sock;  
}

```
    location ~* \.(ico|flv|swf|jpg|jpeg|png|gif|js|css|wav)$ {
            expires max;
    }

    location /secrets/ {
      auth_basic "Restricted";
      auth_basic_user_file /path/to/.htpasswd;
    }

    location /local-secrets/ {
      allow 127.0.0.1;
      deny all;
    }

```

}

…and I’m aware that it’s dangerously wrong. Compounding this is the  
fact  
that it looks - to me at least - intuitively correct. Perhaps I expected  
the  
location parser to be more promiscuous. The second problem is my  
solution:

server {  
listen 80;  
root /www/;

location ~ .php$ {  
fastcgi\_pass unix:php.sock;  
}

```
    location ~* \.(ico|flv|swf|jpg|jpeg|png|gif|js|css|wav)$ {
            expires max;
    }

    location ^~ /secrets/ {
      auth_basic "Restricted";
      auth_basic_user_file /path/to/.htpasswd;

```

location ~ .php$ {  
fastcgi\_pass unix:php.sock;  
}  
location ~\* .(ico|flv|swf|jpg|jpeg|png|gif|js|css|wav)$ {  
expires max;  
}  
}

```
    location ^~ /local-secrets/ {
      allow 127.0.0.1;
      deny all;

```

location ~ .php$ {  
fastcgi\_pass unix:php.sock;  
}  
location ~\* .(ico|flv|swf|jpg|jpeg|png|gif|js|css|wav)$ {  
expires max;  
}  
}  
}

…which is unwieldy, at the least. Is it correct? Is it optimal? Is it  
wise  
to nest these locations? (Would it get more bloated not to?)

My main question is – assuming that the answers to the above are yes –  
is  
there a configuration available or planned that’s as simple as this:

server {  
listen 80;  
root /www/;

_location continue_ ~ .php$ {  
fastcgi\_pass unix:php.sock;  
}

```
    *location continue* ~* 

```

.(ico|flv|swf|jpg|jpeg|png|gif|js|css|wav)$  
{  
expires max;  
}

```
    location /public-secrets/ {
      auth_basic "Restricted";
      auth_basic_user_file /path/to/.htpasswd;
    }

    location /private-secrets/ {
      allow 127.0.0.1;
      deny all;
    }

```

}

By “location continue” I mean the parser to continue matching (sibling)  
locations after a positive match on those expressions. The order of  
matching  
would be the same. Is this / will this be possible?

Thomas

---

<div class="post-metadata">

**Author:** ![tlockney](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5e9695/32.png) [@tlockney](https://www.ruby-forum.com/u/tlockney)\
**Post date:** [April 7, 2011, 8:59pm UTC](https://www.ruby-forum.com/t/the-location-directive/205511/2 "2011-04-07T20:59:39Z")

</div>

> From previous examples posted by our beloved Igor around here (I’m  
> just repeating here), I would say a better (may be event the best)  
> approach is :  
> server {  
> listen 80;  
> root /www/;

location ~ .php$ {  
fastcgi\_pass unix:php.sock;  
}

```
    location ~* \.(ico|flv|swf|jpg|jpeg|png|gif|js|css|wav)$ {
            expires max;
    }

    location /secrets/ {
      auth_basic "Restricted";
      auth_basic_user_file /path/to/.htpasswd;

```

location ~ .php$ {  
fastcgi\_pass unix:php.sock;  
}  
location ~\* .(ico|flv|swf|jpg|jpeg|png|gif|js|css|wav)$ {  
expires max;  
}  
}

```
    location /local-secrets/ {
      allow 127.0.0.1;
      deny all;

```

location ~ .php$ {  
fastcgi\_pass unix:php.sock;  
}  
location ~\* .(ico|flv|swf|jpg|jpeg|png|gif|js|css|wav)$ {  
expires max;  
}  
}  
}

It all relies on the fact that no matter what non-regexp locations are  
tried first (using the “deepest” one to match). You can find a better  
explanation at [How nginx processes a request](http://nginx.org/en/docs/http/request_processing.html)  
(look for “nginx first searches for the most specific…”)

Good luck with it.

## A.

Join me on my nginx cruise : [http://www.nginx-discovery.com](http://www.nginx-discovery.com)

---

<div class="post-metadata">

**Author:** ![tlockney](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5e9695/32.png) [@tlockney](https://www.ruby-forum.com/u/tlockney)\
**Post date:** [April 8, 2011, 3:09pm UTC](https://www.ruby-forum.com/t/the-location-directive/205511/3 "2011-04-08T15:09:08Z")

</div>

On 8 April 2011 04:32, Maxim D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

There were lots of such discussions, and the only expected answer

> to all proposals to add global/continue/whatever locations which  
> alter configuration is: no.
> 
> The reason is simple: with large config it’s practically  
> impossible to find out how requests will be processed when  
> such “global” locations are present.

I should have been clear – global/continue/whatever are not the same  
thing.  
A “continue” location is tested in the normal order. This means there’s  
a  
possibility it’s _not_ processed even if it matches, if it comes after  
a  
normal match-and-break location in nginx’s testing order.

Assuming you meant what I did by “continue”, I’m not sure whether you  
are  
saying simply that it’s difficult for users to understand such configs,  
or  
whether you’re saying the processing actually is undefined.

If it’s the former, then, is it not the case that:

a) (likely very many) large configs wouldn’t be so large if they used  
“continue” locations  
b) the cheapest alternative is nested locations, which are themselves  
difficult to understand, and  
c) existing users need not implement it

The idea is to simplify the configs of new and ordinary users, and to  
provide a compact alternative to common nesting motifs.

If on the other hand you are saying that there are cases where  
processing  
somehow becomes undefined when using a “continue” location, can you  
provide  
an example (which does not occur for an equivalent nested directive)?

Thomas

---

<div class="post-metadata">

**Author:** ![tlockney](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5e9695/32.png) [@tlockney](https://www.ruby-forum.com/u/tlockney)\
**Post date:** [April 8, 2011, 5:54pm UTC](https://www.ruby-forum.com/t/the-location-directive/205511/4 "2011-04-08T17:54:41Z")

</div>

Hello!

On Fri, Apr 08, 2011 at 03:08:44PM +0200, Thomas L. wrote:

> I should have been clear – global/continue/whatever are not the same thing.  
> A “continue” location is tested in the normal order. This means there’s a  
> possibility it’s _not_ processed even if it matches, if it comes after a  
> normal match-and-break location in nginx’s testing order.
> 
> Assuming you meant what I did by “continue”, I’m not sure whether you are  
> saying simply that it’s difficult for users to understand such configs, or

It’s mostly impossible to understand and (more importantly)  
correctly modify such configs once they grow large enough.

> whether you’re saying the processing actually is undefined.

Obviously you may always define how conflicts like

```
location / {
    expires 1d;
}

theoretical continue location ~ \.jpg$ {
    expires max;
}

```

are resolved, e.g. last one wins. But it adds another layer of  
complexity. And one day you’ll find yourself trying to set  
“expires epoch;” for your monitoring pages - just to find out that  
it’s either not set for generated images if you use something like

```
location /monitoring/ {
    expires epoch;
}

```

or php scripts isn’t executed if you disable “continue locations”  
via explicit stop, i.e.

```
location ^~ /monitoring/ {
    ...
}

```

(not even talking about that you actually need another explicit  
stop, as you may still want regexp locations to be processed).

> If it’s the former, then, is it not the case that:
> 
> a) (likely very many) large configs wouldn’t be so large if they used  
> “continue” locations

They will become large eventually anyway. Configs grow over time,  
it’s normal and perfectly understandable. The idea is to encourage  
aproach which is scalable, i.e. will still allow to understand and  
modify config once it has become big enough.

> b) the cheapest alternative is nested locations, which are themselves  
> difficult to understand, and

Not really. You have largely isolated chunk of config which  
fully defines how requests are processed. This is easy enough and  
scales well.

> c) existing users need not implement it

The problem is that bad written configs is something we all have  
to deal on a regular basis - even if we haven’t wrote them.

We’ve all seen configuration hell happening in Apache configs, and  
Igor tried hard to not allow this in nginx keeping complexity as  
low as possible. Sometimes this comes with cost (i.e. you have to  
duplicate some configs) - but it’s well understood and actually  
reduces costs in long run.

> The idea is to simplify the configs of new and ordinary users, and to  
> provide a compact alternative to common nesting motifs.
> 
> If on the other hand you are saying that there are cases where processing  
> somehow becomes undefined when using a “continue” location, can you provide  
> an example (which does not occur for an equivalent nested directive)?
> 
> Thomas

Maxim D.

---

<div class="post-metadata">

**Author:** ![tlockney](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5e9695/32.png) [@tlockney](https://www.ruby-forum.com/u/tlockney)\
**Post date:** [April 8, 2011, 4:33am UTC](https://www.ruby-forum.com/t/the-location-directive/205511/5 "2011-04-08T04:33:19Z")

</div>

Hello!

On Thu, Apr 07, 2011 at 08:47:10PM +0200, Thomas L. wrote:

> Hello list
> 
> I am new to nginx. I put it into production a couple of weeks ago, and I  
> have been very pleased with its efficiency and stability. But I have  
> been wondering about an aspect of the location directive. The only previous  
> discussion I have found of this went dead without resolution (  
> [http://forum.nginx.org/read.php?2,4225](http://forum.nginx.org/read.php?2,4225))

There were lots of such discussions, and the only expected answer  
to all proposals to add global/continue/whatever locations which  
alter configuration is: no.

The reason is simple: with large config it’s practically  
impossible to find out how requests will be processed when  
such “global” locations are present.

> }  
> location /local-secrets/ {  
> listen 80;  
> location ^~ /secrets/ {  
> location ^~ /local-secrets/ {
> 
> …which is unwieldy, at the least. Is it correct? Is it optimal? Is it wise  
> to nest these locations? (Would it get more bloated not to?)

Yes, it’s correct.

I would also recommend wrapping your regular regexp locations into  
location / {} block, i.e.

```
location / {
    ...

    location ~ \.php$ {
        ...
    }
}

location /protected/ {
    auth_basic ...

    location ~ \.php$ {
        ...
    }
}

```

(ideally there should be no regexp locations at all, but I clearly  
understand that it’s mostly impossible when php involved)

> ```
> location /private-secrets/ {
> allow 127.0.0.1;
> deny all;
> }
> 
> ```
> 
> }
> 
> By “location continue” I mean the parser to continue matching (sibling)  
> locations after a positive match on those expressions. The order of matching  
> would be the same. Is this / will this be possible?

No, see above.

Maxim D.
