The location directive

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)

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

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
(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

On 8 April 2011 04:32, Maxim D. [email protected] 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

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.

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 (
RFC: "global" location functionality)

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.