How does 'locate' work?

Hi! I want to protect a directory and its content. The directory is
located in the server in the dir:

/var/www/site.com/public/documents/

So, i have:

location /public/documents/ {
    root /var/www/site.com/;
    auth_basic            "Access restricted.";
    auth_basic_user_file   /private/pass;

}

The thing is, i’ve been toying with the location and root options, with
and without ^ and seems that i can not frigging protect the directory.
So, can someone explain me with practical examples, how does the
location and root parameters work? I read the wiki and can’t get it to
work properly.

Thanks a LOT!

Posted at Nginx Forum:

Hello!

On Wed, Oct 21, 2009 at 04:50:38PM -0400, GAZ082 wrote:

}
This seems to be correct and should work. But see below.

The thing is, i’ve been toying with the location and root options, with and without ^ and seems that i can not frigging protect the directory. So, can someone explain me with practical examples, how does the location and root parameters work? I read the wiki and can’t get it to work properly.

Basic concepts:

  1. nginx uses URI to find out location to use to process request.

  2. Only one location used to process request. Don’t expect
    different locations to be magically combined.

  3. There are normal locations (“location /uri/”) and regexp
    locations (“location ~ regex”). Normal locations use prefix
    matching and most specific match wins, regex locations are applied
    in order and first match wins.

  4. For everything that needs regexp matching nginx uses pcre. See
    man pcre for details.

  5. nginx writes error_log for reason, looking there may help a
    lot.

Practical examples:

  1. Files in /path/to/root/uri/:

    server {
    root /path/to/root;

     location /uri/ {
         # correct root is inherited, no need to set explicitly
         # here; files will be accessed as <root> + <uri>
    
         ...
     }
    

    }

  2. Files in /path/to/root/uri and /path/to/another/root/uri2:

    server {
    root /path/to/root;

     location /uri/ {
         # correct root is inherited, no need to set explicitly
         # here
    
         ...
     }
    
     location /uri2/ {
         root /path/to/another/root;
    
         ...
     }
    

    }

  3. Files in /something/unrelated, should be accessible via /uri/:

    server {
    location /uri/ {
    # + gives extra ‘/uri/’, so we have to
    # use alias instead; alias replaces part matched by
    # location, for /uri/file it will be + “file”

         alias /something/unrelated/;
     }
    

    }

  4. Somebody comes and adds regexp location to the example 1.

    server {
    root /path/to/root;

     location /uri/ {
         ... something ...
     }
    
     location ~ \.php$ {
         fastcgi_pass ...
     }
    

    }

Here fun begins. As long as you have nothing in “something” -
this will work. But once you have essential part of your
configuration there (e.g. auth_basic) - it will work for normal
files, but not for php.

The reason is that instead of “something” nginx will use
configuration from “location ~ .php$”. Remember - only one
location, no magic? While this seems obvious in examples like

location /path/to/ {
    # ... configuration A
}

location /path/to/something/ {
    # ... configuration B
}

it turns to cause lots of conusion in configurations with regexps.

Possible solutions include “^~” (obvious mnemonic: no regex)
location modifier to make “location /uri/” win over regexp
locations:

server {
    root /path/to/root;

    location ^~ /uri/ {
        auth_basic ...
    }

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

This will check authorization on anything under /uri/. But
obviously this won’t allow php files to be passed to backend in
/uri/ subdir. If you want to do both, you have add another
“combined” location, e.g.:

server {
    root /path/to/root;

    location /uri/ {
        # note: allow regex locations, we will catch them
        # individually

        auth_basic ...
    }

    location ~ ^/uri/.*\.php$ {
        # make sure php location won't override our auth_basic

        auth_basic ...
        fastcgi_pass ...
    }

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

But this is really fragile. As soon as new regex location appears

  • you’ll have to add another one to preserve auth_basic. More
    safe aproach is to use nested locations, i.e.:

    server {
    root /path/to/root;

      location ^~ /uri/ {
          # no regexps, please
    
          auth_basic ...
    
          # nested location to handle php
    
          location \.php$ {
              fastcgi_pass ...
          }
      }
    
      location ~ \.php$ {
          fastcgi_pass ...
      }
    

    }

Note that nested locations still may have some inheritance issues
and therefore not documented. Though it’s probably the best available
aproach if you use regexp locations. The only aproach that is
obviously better is not to use regexp locations at all.

If you are still reading, you probably in doubt: how this is
related to original question?

Answer is simple - you can’t expect that “location /uri/” will be
matched without looking for other locations in the same server
block, especially regexp locations. So config snippet you
provided is fundamentally incomplete, it may work or not depending
on other content of your config.

Maxim D.

More safe aproach is to use nested locations, i.e.:

Nested locations?! Awesome!

:slight_smile:

  • Jeff

Note that nested locations still may have some inheritance issues
and therefore not documented.

Maxim D.
Now, we’v got the (nested) Pandora’s box opened (in addition to evil
of if), aren’t we? :wink:

On Thu, Oct 22, 2009 at 3:50 AM, GAZ082 [email protected] wrote:

Hi! I want to protect a directory and its content. The directory is located in the server in the dir:

/var/www/site.com/public/documents/

So, i have:

if you’re using latest development version, try specifying the
location without trailing slash

  • Â Â location /public/documents/ {
  • location /public/documents {

Hello!

On Thu, Oct 22, 2009 at 1:35 AM, Maxim D. [email protected]
wrote:

On Wed, Oct 21, 2009 at 04:50:38PM -0400, GAZ082 wrote:

But this is really fragile. As soon as new regex location appears

  • you’ll have to add another one to preserve auth_basic. More
    safe aproach is to use nested locations, i.e.:

Since which version? I had some problem and using ‘alias /l/$1’ for PHP
scripts because of missing nested location. So it is time to change? :slight_smile:

Bye,
a

Hello!

On Thu, Oct 22, 2009 at 01:52:59PM +0200, Artifex Maximus wrote:

Since which version? I had some problem and using ‘alias /l/$1’ for PHP
scripts because of missing nested location. So it is time to change? :slight_smile:

Nested location are allowed by config syntax from 0.1.0 (first
public release). But they may have various bugs in various
versions. Example I’ve provided should work on all supported
branches including legacy 0.6.*, though I’ve never checked.

Note well: alias directive is one that likely has problems with
nested locations.

Maxim D.

Awesome article. Been trying to tune it up a little, and now i’m getting
a 403 in the directory documents, here is my full site.com config:

server {
listen 80;
server_name www.site.com;
#rewrite ^/(.*) http://site.com/$1 permanent;
access_log /var/www/site.com/log/access.log;
error_log /var/www/site.com/log/error.log;

location / {
    root   /var/www/site.com/public/;
    index  index.html index.htm index.php;

}

location /documents {
    root /var/www/site.com/public;
    auth_basic            "Access restricted.";
    auth_basic_user_file   /var/www/site.com/private/pass;
}

location ~ .php$ {
    #       root /var/www/site.com/public;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param  SCRIPT_FILENAME 

/var/www/site.com/public$fastcgi_script_name;
include /usr/local/nginx/conf/fastcgi_params;
}

# redirect server error pages to the static page /50x.html
#
error_page   500 502 503 504 404 /error/error.htm;
#   location = /var/www/site.com/public/error/ {
#       root   htm;
#    }

}

Permissions on the directory are:

drwxr-xr-x 3 admin admin 4096 Oct 22 15:15 documents

Posted at Nginx Forum:

Hello!

On Thu, Oct 22, 2009 at 01:05:41PM -0400, GAZ082 wrote:

Awesome article. Been trying to tune it up a little, and now i’m getting a 403 in the directory documents, here is my full site.com config:

Is 403 differs from what you expect?

403 is perfectly valid code, and it’s returned by nginx in
serveral situations, including the following you may want to
check:

  1. auth_basic specified in config, but specified
    auth_basic_user_file doesn’t exists

  2. directory index requestd but not allowed (i.e. no index file in
    directory, and autoindex not enabled)

Both should log reason in error_log at error level.

    root   /var/www/site.com/public/;

It’s probably a good idea to move root directive to server{}
level. This will save you some typing in each location.

    index  index.html index.htm index.php;
    
}

location /documents { 

Note that this matches anything that starts from “/documents”,
including /documents.html and so on. Use “/documents/” to match
directory only.

    root /var/www/site.com/public;
    auth_basic            "Access restricted.";
    auth_basic_user_file   /var/www/site.com/private/pass;
}

Otherwise looks perfectly correct. Note well that it has no index
directive, and therefore default index.html will be used.

If you expect this should have the same indices as in “location /”,
you probably have to move index directive from “location /” to
server{} level as well.

location ~ .php$ {

So your .php files in /documents/ won’t be protected. See example
4 (as far as I remember numbering) in my previous message.

Maxim D.

Thanks Maxim for your continuous support and patience, you are a god
send. :slight_smile:

I did not put the root in the server because the password file is
outside the /public directory, it’s one level up, in the private.

I want to only protect all the content inside documents, so i think is
correct as you pointed out.

So, basically, my config file does what i want to acomplish, but still
getting a 403. Perhaps a permission issue? But i have the same owner and
group for files and dirs that are working ok.

Posted at Nginx Forum:

Hello!

On Thu, Oct 22, 2009 at 09:24:35PM -0400, GAZ082 wrote:

Thanks Maxim for your continuous support and patience, you are a god send. :slight_smile:

I did not put the root in the server because the password file is outside the /public directory, it’s one level up, in the private.

Path to password file is path. It has nothing to do with root.

I want to only protect all the content inside documents, so i think is correct as you pointed out.

So, basically, my config file does what i want to acomplish, but still getting a 403. Perhaps a permission issue? But i have the same owner and group for files and dirs that are working ok.

It’s unlikely to be permission issue. I’ve pointed out two
possible reasons. Try looking into error log for more details.

Maxim D.