vraagdtc
vraagdtc

Reputation: 11

How to prevent rewrite after deny

I have a website inside "/directory/", and a special variation of the website inside "/directory/subdirectory/" which should only be accessible by a few specific IP addresses. The subdirectory, however is a virtual URL, the website code is still in the parent directory called "directory" in this example. So I need rewrites.

This is the relevant part of my current nginx config file:

location /directory {
    # here are various rewrites for my website

    location /directory/subdirectory/ {
        allow 10.0.0.0/8; # example range of IP addresses allowed 
        deny all; # disable access for others
        rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last; # the website location is still in the parent folder but the PHP code knows this specific version is to be used when the user surfs into subdirectory, which is why there is this rewrite
    }

    try_files $uri $uri/ /directory/index.php?q=$uri&$args;
}

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi.conf;
    fastcgi_read_timeout 43200; 
}

The problem I'm facing: I don't know how to stop the execution as soon as the "deny all" hits. If you're surfing into the subdirectory, the rewrite always executes, no matter if your IP is allowed or not by the directives above it. So someone surfing to the subdirectory with an IP address which is not allowed can see the website inside subdirectory, which is of course not what I want. If I comment out the rewrite, then the allow/deny directives work as they are supposed to.

So: how can I specify this rewrite is ONLY to be executed if the visitor is not denied? Tried adding "error_page 403 /403.html;" to that location after the "deny all;" directive but it only changes the 403 page (and can only be seen again when commenting the rewrite rule in the subdirectory). Been searching the net for days already with various search terms to make this happen, and been fiddling with variations of the config, but to no avail.

Also: the "deny all" doesn't work anymore as soon as I surf to an URL inside subdirectory, ending with ".php". I assume it is because of the "location ~ .php$" directive, getting priority for some reason over the nested location directives above. I could get around this by doing:

location ^~ /directory/subdirectory/ {
    allow 10.0.0.0/8; # example range of IP addresses allowed 
    deny all; # disable access for others
    rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last;
}

location /directory {
    # here are various rewrites for my website

    try_files $uri $uri/ /directory/index.php?q=$uri&$args;
}

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi.conf;
    fastcgi_read_timeout 43200; 
}

Now the "location ^~ /directory/subdirectory/" directive gets priority over the "location ~ .php$" directive which makes the "deny all" work but I don't know if that's the way to go since it doesn't seem like the most "clear to read" solution because I move something from within the "directory/" location out of that location block. And also, that still doesn't solve my main problem (only making the "rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last;" execute for allowed IP addresses and not those getting denied by the "deny all".

Thank you.

Upvotes: 1

Views: 2219

Answers (1)

Petski
Petski

Reputation: 361

The issue you are facing is related to the precedence/order in which nginx handles it's directives. A detailed explanation can be found here (hats off to the author!):

In their execution order the phases are post-read, server-rewrite, find-config, rewrite, post-rewrite, preaccess, access, post-access, try-files, content, and finally log

Since "rewrite" comes before "access", the "rewrite" directive is handled first.

Since "if" is handled in "rewrite"-phase as well, one could write:

location ~ \.php$ {
 if ($remote_addr != "172.17.0.1") {
  return 403;
 }
 rewrite ^ /your-redirect last;
}

Upvotes: 2

Related Questions