# Rewriting

**URL:** <https://www.ruby-forum.com/t/rewriting/245391>\
**Category:** NGINX\
**Created:** [May 23, 2013, 10:12pm UTC](https://www.ruby-forum.com/t/rewriting/245391 "2013-05-23T22:12:46Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rafa\_F](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/958977/32.png) [@Rafa\_F](https://www.ruby-forum.com/u/Rafa_F)\
**Post date:** [May 23, 2013, 10:12pm UTC](https://www.ruby-forum.com/t/rewriting/245391/1 "2013-05-23T22:12:46Z")

</div>

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/](http://mysite.com/) request but in case  
[http://mysite.com/index.php](http://mysite.com/index.php) rewrite is none and request processed by  
location ~ .php$ rule. Why??

Thanks!

---

<div class="post-metadata">

**Author:** ![wishmaster](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f4b2a3/32.png) [@wishmaster](https://www.ruby-forum.com/u/wishmaster)\
**Post date:** [May 23, 2013, 11:48pm UTC](https://www.ruby-forum.com/t/rewriting/245391/2 "2013-05-23T23:48:36Z")

</div>

Hello,

[http://nginx.org/en/docs/http/request\_processing.html](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$  
{  
…  
}

}

---

<div class="post-metadata">

**Author:** ![wishmaster](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f4b2a3/32.png) [@wishmaster](https://www.ruby-forum.com/u/wishmaster)\
**Post date:** [May 24, 2013, 8:02am UTC](https://www.ruby-forum.com/t/rewriting/245391/3 "2013-05-24T08:02:32Z")

</div>

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](http://akbmaster.server.com),  
request: “GET / HTTP/1.1”, host: “[akbmaster.server.com](http://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,

---

<div class="post-metadata">

**Author:** ![wishmaster](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f4b2a3/32.png) [@wishmaster](https://www.ruby-forum.com/u/wishmaster)\
**Post date:** [May 25, 2013, 12:07pm UTC](https://www.ruby-forum.com/t/rewriting/245391/4 "2013-05-25T12:07:58Z")

</div>

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](http://akbmaster.server.com), request: “GET /  
> HTTP/1.1”, host: “[akbmaster.server.com](http://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. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![wishmaster](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f4b2a3/32.png) [@wishmaster](https://www.ruby-forum.com/u/wishmaster)\
**Post date:** [May 24, 2013, 6:59pm UTC](https://www.ruby-forum.com/t/rewriting/245391/5 "2013-05-24T18:59:52Z")

</div>

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._

---

<div class="post-metadata">

**Author:** ![wishmaster](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f4b2a3/32.png) [@wishmaster](https://www.ruby-forum.com/u/wishmaster)\
**Post date:** [May 25, 2013, 5:36pm UTC](https://www.ruby-forum.com/t/rewriting/245391/6 "2013-05-25T17:36:54Z")

</div>

Hello,

Because you placed root inside the location /.  
As [http://wiki.nginx.org/Pitfalls](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](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](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](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.

---

<div class="post-metadata">

**Author:** ![wishmaster](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f4b2a3/32.png) [@wishmaster](https://www.ruby-forum.com/u/wishmaster)\
**Post date:** [May 27, 2013, 4:26am UTC](https://www.ruby-forum.com/t/rewriting/245391/7 "2013-05-27T04:26:47Z")

</div>

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/](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 🙂

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](http://127.0.0.1/unav/img.png)  
curl -i [http://127.0.0.3/unav/img.png](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/](http://127.0.0.1/sample/)  
curl -i [http://127.0.0.3/sample/](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](http://nginx.org/r/geo) for the syntax.

## f

Francis D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)
