how to restrict access to directory and subdirs

124,403

Solution 1

to restrict access to multiple directories in nginx in one location entry do

...
location ~ /(dir1|dir2|dir3) {
   deny all;
   return 404;
}
...

Solution 2

It's because the "root" directive matches before the "deny" directive can be matched. Reverse the order of your directives and it should work:

...
location /testdir {
  deny all;
  return 404;
}
location ~* ^.+\.(jpg|txt)$ {
  root   /var/www/site;
}
...

Solution 3

To ensure that the testdir match is chosen instead of the jpg/txt match, use the following locations:

location ^~ /testdir {
  deny all;
  return 404;
}
location ~* ^.+\.(jpg|txt)$ {
  root   /var/www/site;
}

In your example, you have two types of locations. location /testdir is a prefix location, as it has no tilde (~) between location and /testdir.

location ~* ^.+\.(jpg|txt)$ is a regex location (a case-insensitive one, due to the * directly after the tilde). From the nginx documentation:

To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

The problem here, is that your testdir location is being remembered, but then the jpg/txt location is selected during the regex stage, as it matches. The following note from the documentation is what I based my solution (given above) upon:

If the longest matching prefix location has the “^~” modifier then regular expressions are not checked.

Solution 4

location /foo {
    deny all;
    return 404;
}

This will give you a 403 all the time because of the deny all... When you want the server to give you a 404 just only return a 404... like so:

location /foo {
    return 404;
}
Share:
124,403

Related videos on Youtube

Admin
Author by

Admin

Updated on September 17, 2022

Comments

  • Admin
    Admin almost 2 years

    I need to restrict access to any files or subdirs in direstory "testdir". My conf:

    ...
    location ~* ^.+\.(jpg|txt)$ {
                root   /var/www/site;
            }
    location /testdir {
            deny all;
            return 404;
            }
    ...
    

    In my configuration I have no restrictions on /testdir/jpg_or_txt-files. How to do it?

    • Jonesome Reinstate Monica
      Jonesome Reinstate Monica over 9 years
      Note, in my experience, the location function only works properly when running nginx on linux. When running on windows, we had trouble with this not working ...
  • Stillmatic1985
    Stillmatic1985 about 9 years
    You should return 403 and not 404.
  • Don Wilson
    Don Wilson about 5 years
    returning 403 gives a hint that the folder exists, a 404 gives no evidence of the folder existing at all
  • Stefan Fabian
    Stefan Fabian over 4 years
    Most of all it doesn't really make sense to first deny and then return 404, does it? The deny should already block the request and if you want to return 404, the statement return 404 should be sufficient.
  • RemyNL
    RemyNL over 4 years
    This is not how nginx works. It first matches prefixes, remembers the longest match and after that checks the regex’s. When it finds a matching regex, it will use that (without checking any of the other) if it finds none, it’ll use the remembered prefix location
  • Admin
    Admin almost 2 years
    This rule will not only forbid access to the dir1, dir2 and dir3 locations but to any location containing dir1, dir2 or dir3, for example dir1xxx would be forbidden.
  • Admin
    Admin almost 2 years
    In order to forbid only the exact folder, you can use location ~ "/(dir1/|dir2/|dir3/)"