Disable auth_basic for unique (set of) URL

Hello,

I am using the auth_basic directive to restrict access to a whole server
(auth_basic server-wide set, not in any particular location).
Since I am using php, I am also using:

location ~ .php$ {
FastCGI stuff here…
}

to forward my request to the PHP application.

Now, I would like to remove the auth_basic authentication for a very
unique
and specific location: thisfile.php

I first tried:

location ~ .php$ {
location = /thisfile.php {
auth_basic off;
}
FastCGI stuff here…
}

but Nginx said:
nginx: [emerg] location “/thisfile.php” is outside location “.php$” in
…/nginx/conf.d/mystupid.conf:69
nginx: configuration file …/nginx/nginx.conf test failed

I then tried:

location ~ .php$ {
location ~ ^/thisfile.php$ {
auth_basic off;
}
FastCGI stuff here…
}

But of course now the FastCGI part does not server the request and the
PHP
file is sent for download…

What king of clean solution do I have?
Am I forced to place the auth_basic in all my ‘location’ blocks but one,
which would be for ‘thisfile.php’?

Thanks,

B. R.

I found inspiration
herehttp://serverfault.com/questions/119076/how-to-use-fastcgi-globally-and-basic-auth-in-sublocations-in-nginx
.

I then tried to solve my problem with:

location /thisfile.php {
auth_basic off;

Start of exact copy

location ~ \.php$ {
    FastCGI stuff here...
}

End of exact copy

}

location ~ .php$ {
FastCGI stuff here…
}

I don’t like this solution because it makes me copying my FastCGI work.
What if one day I am to modify it? I’ll probably forget there are 2
places
to check…

But it seems to work.

Any better idea?

Another point:
If I set ‘location = /thisfile.php’ rather than ‘location
/thisfile.php’,
Nginx insults me with ‘nginx: [emerg] location “.php$” cannot be inside
the exact location “/thisfile.php”’ again. Bug or feature?


B. R.

On Thu, Dec 27, 2012 at 09:57:16AM -0500, B.R. wrote:

Hi there,

How nginx processes a request is probably useful
to read.

nginx has that one request is handled in one location. Having learned
those rules, I find nginx.conf (relatively) easy to read.

}

location ~ .php$ {
FastCGI stuff here…
}

I don’t like this solution because it makes me copying my FastCGI work.

I don’t have a problem with copying the FastCGI stuff. I’d probably just
use “include my-fastcgi-config” in two places and not worry about it.

I don’t like the solution above because it doesn’t do what you want. It
will ask for authentication when you request /thisfile.php.

What if one day I am to modify it? I’ll probably forget there are 2 places
to check…

Either use an aid to remember, or don’t repeat the things that are
common to multiple places in the config file. You can use the nginx
“include” directive; or you can use whatever macro processor you prefer
to generated nginx.conf.

But it seems to work.

Test again. Use “curl” – it doesn’t tend to use a cache or hide things
from you.

Any better idea?

location = /thisfile.php {
auth_basic off;
include my-fastcgi-config;
}
location ~ .php$ {
include my-fastcgi-config;
}

But really I’d probably try to avoid the top-level regex location. And,
depending on what else is involved, I might just “include fastcgi.conf”
once at server level, and then “fastcgi_pass” in the locations where I
want the request to be handled by the fastcgi server.

Another point:
If I set ‘location = /thisfile.php’ rather than ‘location /thisfile.php’,
Nginx insults me with ‘nginx: [emerg] location “.php$” cannot be inside
the exact location “/thisfile.php”’ again. Bug or feature?

That nginx reports a dubious config? Feature.

That you consider it an insult? Bug.

In my opinion.

f

Francis D. [email protected]

On Sat, Dec 29, 2012 at 02:48:16PM -0500, B.R. wrote:

Hi there,

Thanks Francis for your insights. Your message has been a great help.

You’re welcome.

Despite what you said, I don’t have any cache configured yet (low-traffic
server) and the configuration I use requests authentification for all .php
file but the ‘thisfile.php’. On the other hand, the browser I use doesn’t
store any cache either.

I was unclear. The “cache” I mentioned was not intended to refer to the
server at all.

Browsers tend to cache things, including user/pass credentials
previously
provided. So “merely” hitting reload in a typical browser may auto-send
credentials without showing you that that is happening.

curl tends not to do that. If you don’t include the credentials on the
command line each time, you will get the 401 response each time.

So curl is particularly good to test with when changing server
configuration, as it starts from the same state each time.

I’d like more than theory on that particular point…

http://nginx.org/r/location

Given only “location /thisfile.php” and “location ~ .php$”, a request
for “/thisfile.php” will match the second location, not the first.

When I test using a configuration like that, I get the 401 response for
all “.php” requests. I can’t explain how your nginx acts differently.

I’m not a pro of cURL, never have been… I’m encountering some errors I am
having a hard time understanding.

I tend to test with, for example,

curl -i http://localhost/thisfile.php

“-i” shows the http response headers as well as the body; error states
are usually shown in those headers.

If the response to any request is not what you expect it to be, the
error
log and copy-paste’ing the request and response to the mailing list may
help someone explain it.

What I didn’t understand about the error is that placing a ‘~ .php’
catch-all PHP reges inside ‘location = /thisfile.php’ isn’t allowed but is
allowed inside ‘location /thisfile.php’… Which is not more generic than
the previous one.

“location /thisfile.php” is a prefix match. A request for
/thisfile.phpsome/thing can match this location. So nesting a location
within it can be useful.

“location = /thisfile.php” is an exact match (of uri, not considering
query string). Only one request can match this location. Nesting another
location within it is not useful – it would either always match or
never
match, and the person writing the config can determine which it would
be and either include or exclude the extra configuration
unconditionally.

Tell me how many PHP files will match each one of the ‘location’ clauses.
I was excepting the same behavior regarding both those locations, either
both generating an error or both silent… Which is not the case.

http://nginx.org/r/location

Some locations can be nested, some can’t.

And the example there hopefully allows you to determine which location
will be used for each request.

Assuming exactly these two top-level locations, your prefix match
“/thisfile.php” location will be used for all requests that start
“/thisfile.php” and do not end in “.php” (where “end” means “just before
the first # or ?”). Because of that, your nested “~ .php$” location
will not match any request.

Your top-level “~ .php$” will match all requests that end “.php”.

Whether those requests correspond to php files is a separate matter.

f

Francis D. [email protected]

And… thanks again for all that information.
Greatly appreciated!

As I told you, I configured my browser (Firefox) to never store anything
(passwords, cache, cookies: basically anything) at the end of a browsing
session.
Basically closing the browser clears everything up.

Using cURL, I had some errors about an IPv6 address which I do not know.
I checked with traceroute that the domain name was correctly resolved to
the
IPv4 address of my server, but the IPv6 was not mine. The traceroute
didn’t
end up with anything since my server drops ICMP traffic.
I basically tried ‘curl -o file.out http://domain.name/thisfile.php’,
nothing fancy.
Using the right domain name (and not any other or even IP) is important
since my Nginx configuration serves content based on the requested name.

Rather than losing time with cURL, I checked that a wrong configuration
doesn’t serves ‘thisfile.php’ and that a wrong configuration does.
Changing behavior allows me to confirm I don’t have cache.

Thanks agains for all the details about the different types of
'location’behavior.
I must have read something about that quite some time ago. It went
totally
out of my mind since then.

Problem solved, configuration cleared and tweaked for better
performance.
I can’t thank you enough (that is starting to be too much :oP)


B. R.

Thanks Francis for your insights. Your message has been a great help.

Despite what you said, I don’t have any cache configured yet
(low-traffic
server) and the configuration I use requests authentification for all
.php
file but the ‘thisfile.php’. On the other hand, the browser I use
doesn’t
store any cache either.
I’d like more than theory on that particular point…
I’m not a pro of cURL, never have been… I’m encountering some errors I
am
having a hard time understanding.

You are right about that include usage. I havent’ eventhought about it.
How
stupid I can be sometimes.

I’ll also follow your good advice on separating config/invocation of
FastCGI and I’ll clean up the ‘global’ inclusion.

What I didn’t understand about the error is that placing a ‘~ .php’
catch-all PHP reges inside ‘location = /thisfile.php’ isn’t allowed but
is
allowed inside ‘location /thisfile.php’… Which is not more generic
than
the previous one.
Tell me how many PHP files will match each one of the ‘location’
clauses.
I was excepting the same behavior regarding both those locations, either
both generating an error or both silent… Which is not the case.

I’ll consider the first 2 of your last 3 lines as a lack of
understanding
of the problem I was pointing at. That could have been insulting
In my opinion.


B. R.

I’ll try all that.

Happ new year btw ;o)


B. R.

On Sat, Dec 29, 2012 at 07:26:58PM -0500, B.R. wrote:

Hi there,

You’ve got a working nginx.conf, so all is good.

I’ll just add some small points about curl, which may make future
testing easier.

Using cURL, I had some errors about an IPv6 address which I do not know.

It is possible to use “-4” to tell curl to only resolve names to IPv4
addresses – that might avoid that problem.

Using the right domain name (and not any other or even IP) is important
since my Nginx configuration serves content based on the requested name.

You can use something like

curl -i -H Host:domain.name http://127.0.0.1/thisfile.php

to connect to the desired address, and then send the required domain
name in the Host: header which nginx will use to choose the server{}
configuration to use.

Problem solved, configuration cleared and tweaked for better performance.
I can’t thank you enough (that is starting to be too much :oP)

Glad it’s all working now.

All the best,

f

Francis D. [email protected]