2

I have the following setup

  • Master server - call it https://master.com
  • Slave server - call it https://slave.com

Both run Nginx on Ubuntu 16.04

On the master server I have created the following configuration block in my /etc/nginx/sites-available/default file

location /test
{
 rewrite ^/test(.*) /$1 break;
 proxy_pass https://slave.com;
 proxy_read_timeout 240;
 proxy_redirect off;
 proxy_buffering off;
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto https;
}

A service nginx reload later on master.comand I can do the following

  • Browse to https://master.com/test and view the output from slave.com\index.php.
  • Browse to https://master.com/test/test.txtand see the text in the file slave.com\test.txt
  • Browse to https://master/com/test/test.jpg and see the image in the file slave.com\test.jpg.

However, I cannot do any of the following

  • Browse to https://master.com/test/test.phpwhich instead of showing me the output from https://slave.com/test.php shows me a 404 error message
  • Browse to https://master.com/test/adminer/adminer.phpwhich instead of showing me the login screen for the Adminer instance on the slave, https://slave.com/adminer/adminer.phpshows me the login screen for the Adminer instance on master.comi.e. https://master.com/adminer/adminer.php

This is clearly because I am missing something in my Nginx configuration on master.com. However, I am unable to see what that might be.

In the interests of completeness, here is my configuration on both servers:

Ubuntu - 16.04.3 Nginx - 1.10.3 PHP - 7.0.22

I should explain why the ^~ is required since this is not clear from my original question. I have another block setup to handle PHP scripts on master.com.

location ~ \.php$ 
{
 try_files $uri =404;
 fastcgi_split_path_info ^(.+\.php)(/.+)$;
 fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
 fastcgi_index index.php;
 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 include fastcgi_params;
}

Because of the way Nginx processes these directives this block takes priority when it comes to handling .php files and master.com ends up looking locally for .php scripts that are actually on slave.com. The only way to avoid this is to use ^~

halfer
  • 19,824
  • 17
  • 99
  • 186
DroidOS
  • 8,530
  • 16
  • 99
  • 171

1 Answers1

8

Your approach is wrong. Inside the block which handles /test your rewrite it and send it out of the block. The proxy_pass never actually happens because the new URL doesn't have /test in it. Solution is simple, don't use rewrite

location /test/
{
 proxy_pass https://slave.com/;
 proxy_read_timeout 240;
 proxy_redirect off;
 proxy_buffering off;
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto https;
}

Appending / at the end of the location path and also the proxy_pass server will make sure what is after /test/ is sent to your proxy_pass address

Edit-1

Here is a sample test case I had set before posting this answer.

events {
    worker_connections  1024;
}
http {
server {
   listen 80;

   location /test1 {
     proxy_pass http://127.0.0.1:81;
   }

   location /test2 {
     proxy_pass http://127.0.0.1:81/;
   }

   location /test3/ {
     proxy_pass http://127.0.0.1:81;
   }

   location /test4/ {
     proxy_pass http://127.0.0.1:81/;
   }

}

server {
   listen 81;

   location / {
     echo "$request_uri";
   }
}
}

Now the results explains the difference between all 4 location blocks

$ curl http://192.168.33.100/test1/abc/test
/test1/abc/test

$ curl http://192.168.33.100/test2/abc/test
//abc/test

$ curl http://192.168.33.100/test3/abc/test
/test3/abc/test

$ curl http://192.168.33.100/test4/abc/test
/abc/test

As you can see in /test4 url the proxied server only sees /abc/test

Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
  • I have upvoted your answer because you rightly mention that I need the `/`terminating slash on `/test`. However, it is not quite the right answer. The `rewrite`is required since on the destination server the resource requested is in document root, not in a subfolder `/test`. I remembered that I had run into this issue a while ago and had got the [https://stackoverflow.com/questions/29212655/nginx-php-scripts-not-being-called-from-reverse-proxy](solution) on SO from @SeriousDron. To cut a long story short `location /test/`needs to be changed to read `location ^~/test/`and it all works! – DroidOS Sep 11 '17 at 12:39
  • @DroidOS, the answer is correct and you don't need a rewrite. You would need `^~` if there is another location which is handling your request because of the priority order. So if you check my edit you will see why and when a rewrite is not needed – Tarun Lalwani Sep 11 '17 at 13:42
  • This is such a pain. When I use 'location /' it works When I use 'location anything else it fails with 404 not found. nginx sucks, I'm going to try something else – Paul McCarthy Mar 08 '23 at 12:43