Rewriting

Hi,
I use opencart with nginx+php-fpm. Sometimes it is necessary to redirect
all clients, except admin (190.212.201.0/24), to “Service unavailable”
page which is simple index.html file with logo, background image and
some text, located in /unav directory.
Below some of nginx.conf

location / {

if ($remote_addr !~ ‘190.212.201.[0-9]{0,3}’) {
rewrite ^/(.*)$ /unav/$1 break;
return 403;
}
try_files $uri $uri/ @opencart;
}

location ^~ /unav {
}

location @opencart {
rewrite ^/(.+)$ /index.php?route=$1 last;
}

[…skipped…]

location ~ .php$ {

     try_files      $uri =404;
     fastcgi_read_timeout 60s;
     fastcgi_send_timeout 60s;
     include           myphp-fpm.conf;

                }

Problem is in rewriting.
This rule

rewrite ^/(.*)$ /unav/$1 break;

rewrite ONLY http://mysite.com/ request but in case
http://mysite.com/index.php rewrite is none and request processed by
location ~ .php$ rule. Why??

Thanks!

Hello,

http://nginx.org/en/docs/http/request_processing.html

Because in this case you need to place your rule in server block if you
would like to be valid for all custom defined locations in your config
For example:

server
{
listen 80;

if ($remote_addr ~ ‘192.168.1.25’)
{
return 403;
}

location /
{

}

location ~ .php$
{

}

}

Off course, you right. Thanks.

if ($remote_addr !~ ‘190.212.201.[0-9]{0,3}’) {
rewrite ^/(.*)$ /unav/$1 break;
}

location / {

}

But in log

2013/05/24 08:49:45 [error] 76017#0: *1910 open()
“/usr/local/www/akbmaster/unav/unav/index.html” failed (2: No such file
or directory), client: 190.212.201.198, server: akbmaster.server.com,
request: “GET / HTTP/1.1”, host: “akbmaster.server.com

I see twice rewriting.
I have rewritten rule like this and this solved twice rewriting
problem.
rewrite ^/([^/]*)$ /unav/$1 break;

Can you explain me why in my situation nginx have rewritten request
twice?

Cheers,

On Fri, May 24, 2013 at 09:01:58AM +0300, wishmaster wrote:

Hi there,

You’ve got a few different things happening here, and I suspect that the
combination leads to you not getting the results you want.

if ($remote_addr !~ ‘190.212.201.[0-9]{0,3}’) {
rewrite ^/(.*)$ /unav/$1 break;
}

So if I request “/file.php”, this will rewrite to “/unav/file.php”,
which probably doesn’t exist, so I’m going to get a 404 unless you
handle
it carefully.

2013/05/24 08:49:45 [error] 76017#0: *1910 open()
“/usr/local/www/akbmaster/unav/unav/index.html” failed (2: No such file or
directory), client: 190.212.201.198, server: akbmaster.server.com, request: “GET /
HTTP/1.1”, host: “akbmaster.server.com

I see twice rewriting.

The initial request was for “/”. The explicit rewrite will make
that be “/unav/” (presuming that the rewrite applies here). In the
matching location{}, “/unav/” corresponds to a directory, not a file,
so there is an implicit rewrite to “/unav/index.html”. This then
goes through the config again, and the explicit rewrite makes that
“/unav/unav/index.html”. In the matching location{}, that does not
correspond to anything on the filesystem, hence 404.

I have rewritten rule like this and this solved twice rewriting problem.
rewrite ^/([^/]*)$ /unav/$1 break;

What happens with that if my initial request is for “/dir/file.php”?

Back you your original issue:

I use opencart with nginx+php-fpm. Sometimes it is necessary to redirect all
clients, except admin (190.212.201.0/24), to “Service unavailable” page which is
simple index.html file with logo, background image and some text, located in /unav
directory.

So if I ask for “/dir/file.php” during this time, what response do you
want
me to get?

The contents of one file? A redirection to a separate url? Something
else?

When you can answer that question, you’ll have a better idea of the
configuration you need.

I suspect that the final logic will be something like:

if this is not an admin address
if the request is for /unav/something, then serve the file
else return http 503 with the content corresponding to
/unav/index.html
else
give full normal access to the site

and that that can be done with “if” and “rewrite”, possibly helped by
“map”; but the details depend on what exactly you want.

f

Francis D. [email protected]

Pure wild guess:

Maybe a missing trailing slash in the request resulting in a temporary
redirection (and then processed again)?
Have you checked the requests made on the client side for any sign of
unwanted redirection? You could then use them to correct your rewrite
directive.

Hope I helped,

B. R.

Hello,

Because you placed root inside the location /.
As http://wiki.nginx.org/Pitfalls your root should also be placed in the
server block.

Example:

server {
listen 80;

             root            /usr/local/www/test;

             if ($remote_addr ~ '192.168.1.25')
             {
                 rewrite ^/(.*)$ /unav/index.html break;
             }

             location / {
             index index.html;
             }

             location /index.php {
                     ...
             }

     }

}

Example content of index.html in /usr/local/www/test is “test”
Example content of index.html in /usr/local/www/test/unav is “unav dir”

Let we say your server is on 192.168.1.24:

  • when you access http://192.168.1.24/index.html from host 192.168.1.25
    you will see in the browser index with content “unav dir”.
  • when you access http://192.168.1.24/index.php from host 192.168.1.25
    you will see in the browser index with content “unav dir”.
  • when you access http://192.168.1.24/index.html (or index.php) from
    another host for example 192.168.1.24 or 192.168.1.23 you will see the
    content of index.html (index.php) from your config. In the example is
    content “test” of index.html and phpinfo() in the index.php.

On Sat, May 25, 2013 at 02:40:37PM +0300, wishmaster wrote:

[Back to the list]

Hi there,

I suspect that the final logic will be something like:

if this is not an admin address
if the request is for /unav/something, then serve the file
else return http 503 with the content corresponding to /unav/index.html
else
give full normal access to the site

My logic is: for all requests (from not an admin) like http://example.org/
use rewriting and show for clients simple temp html page.

I think that that statement is not specific enough for what you actually
want.

Because your html page “/unav/index.html” will include an image
“/unav/img.png”, and you want that not to count as “all requests”.

But I think, I have solved it :slight_smile:

If this does what you want it to, that’s good.

When I tested, I saw some problems.

if ($remote_addr ~ ‘admin_IP’) {
rewrite ^/(.*)$ /unav/$1 last;
}

    location ^~ /unav/ {
    try_files $uri $uri/ /index.html;
    }

That will serve the content of /unav/index.html for all requests (unless
you have an /unav/unav/img.png, for example), but it goes through lots
of rewrites to get there.

    location / {

            try_files $uri $uri/ @opencart;
    }

    location @opencart {
            rewrite ^/(.+)$ /index.php?_route_=$1 last;
    }

… and so on …

My suggestion:

use “geo” or “map” or even “if” to set a variable $site_looks_down,
which is “1” for users and “0” for admins.

if that variable is true, do nothing special for /unav/* urls, and
return
503 for the rest.

have the 503 error return the content of /unav/index.html

have /unav/index.html include links like /unav/img.png

Overall, this is something like:

http {
geo $site_looks_down {
default 1;
127.0.0.3 0;
}
server {
if ($site_looks_down) {
rewrite ^/unav/ $uri last;
return 503;
}
error_page 503 /unav/index.html;
location ^~ /unav/ {
}
# extra location{}s and server-level config here
}
}

Now you can do things like

curl -i http://127.0.0.1/unav/img.png
curl -i http://127.0.0.3/unav/img.png

and you should see the same image response, while things like

curl -i http://127.0.0.1/sample/
curl -i http://127.0.0.3/sample/

should give you different responses – one “503 unavailable”, and one
correct (maybe 404, maybe useful content).

Change the “default” value to 0, or (better) just remove the if() block,
to make the site available to all again.

See documentation at things like Module ngx_http_geo_module for the syntax.

f

Francis D. [email protected]