5

I'm setting up a reverse proxy on Nginx. I need it to listen to multiple ports. I then would like to hit the exact same port on the backend server. Like this: http://frontendserver:9000 -> http://backendserver:9000.

Here's what I thought would work

   ## server configuration
    server {

        listen 9000 ;
        listen 9001 ;
        listen 9002 ;
        listen 9003 ;
        listen 9004 ;
        listen 9005 ;
        listen 9006 ;
        listen 9007 ;
        listen 9008 ;
        listen 9009 ;

        server_name frontendserver;

        if ($http_x_forwarded_proto = '') {
            set $http_x_forwarded_proto  $scheme;
        }

        location / {
                proxy_read_timeout  900;
                proxy_pass_header   Server;
                proxy_cookie_path ~*^/.* /;
                proxy_pass         http://backendserver:$server_port/;
                proxy_set_header    X-Forwarded-Port  $server_port;
                proxy_set_header    X-Forwarded-Proto $http_x_forwarded_proto;
                proxy_set_header    Host              $http_host;
                proxy_set_header    X-Forwarded-For   $proxy_add_x_forwarded_for;
        }
    }

but, it gives me a 502 Bad Gateway error. Any clues why this is, or if there is another way of doing this that would work as explained above?

If i change:

proxy_pass         http://backendserver:$server_port/;

to

proxy_pass         http://backendserver:9000/;

it works just fine, that of course defeats the purpose...

stuff22
  • 151
  • 1
  • 3
  • Bad gateway suggests your proxy_pass isn't working properly. Try hard coding in a single server / port, if it works you know where to look. – Tim Mar 29 '16 at 18:45
  • 1
    I did. If you take a look at the last few lines of the question, i'm changing the variable to port number 9000. – stuff22 Mar 29 '16 at 19:00
  • 1
    Ok. If you have the module headers_more installed add something like this in your location, as a debugging aid, then curl the server and see what comes back in the variables. add_header Z_PORT "$server_port";add_header Z_URL "http://backendserver:$server_port/"; – Tim Mar 29 '16 at 19:19
  • added add_header Z_URL "backendserver:$server_port/" always ; and got this back: "Z_URL backendserver:9000". So, in other words, i got back what I expect, but it does not work still. Still getting bad gateway. Do I need to escape something maybe when it's in the proxy_pass block? – stuff22 Mar 29 '16 at 20:19
  • Not really sure, try some experimentation perhaps. Also try curling the proxy from the nginx box to test that step. – Tim Mar 30 '16 at 00:01
  • Have you tried to set $backendserver "backendserver:$server_port"; and than use proxy_pass http://$backendserver; – Jens Bradler Jul 11 '18 at 13:38
  • I never useed the following construction: ``` if ($http_x_forwarded_proto = '') { set $http_x_forwarded_proto $scheme; } ``` Instead I would purpose declare the following for each port: ```server { listen 9000; return 301 http://backendserver$server_port; } ``` – Dmitriy Kupch Dec 05 '18 at 21:32
  • 1
    The `return` statement would require the backend servers to be publicly available though, no? – Tommiie Jan 15 '19 at 10:37
  • Are the backend servers in the same network as your nginx? Because you have `proxy` in the tags. As far as I know: it is still not possible to reach "backend" servers behind a corporate http connect proxy (at least with vanilla nginx). – uav Dec 13 '20 at 00:29

1 Answers1

1

I prepared the directories /var/www/9000 which only contains one file index.html with content of the port corresponding to the path name.

server {
        listen 81;
        server_name example.com;
        location ~ /([^/]+) {
                proxy_set_header Host '10.20.30.40';
                proxy_pass http://10.20.30.40:$1/;
        }
}
server {
        listen 9000;
        server_name default;
        root /var/www/9000;
        try_files $uri $uri/index.html;
}
server {
        listen 9001;
        server_name default;
        root /var/www/9001;
        try_files $uri $uri/index.html;
}
server {
        listen 9002;
        server_name default;
        root /var/www/9002;
        try_files $uri $uri/index.html;
}

I edited my hosts file to contain my server's IP 10.20.30.40 exmaple.com so I can test without the need on a DNS server.
Then I opened my browser with the address http://example.com:81/9000. Content shows corresponding to the port number I supply through the location.

Then I thought it might be a problem with the $server_name variable so I made a second test.

server {
        listen 82;
        server_name example.com;
        location / {
                proxy_set_header Host '10.20.30.40';
                proxy_pass http://10.20.30.40:90$server_port/;
        }
}
server {
        listen 9082;
        server_name default;
        root /var/www/9082;
        try_files $uri $uri/index.html;
}

Now I'm opening my browser with http://example.com:82 and content shows 9082 as expected.

If you supply anything other than the upstream group name it gets treated as domain name. That's when you get the Bad gateway error.

Here is your solution:
You need to use map to translate the requested port to an upsteam group and use this in the proxy_pass.

upstream mycustombackend9082 {
        server 10.20.10.48:9082;
}
map $server_port $backendname {
        82      mycustombackend9082;
}
server {
        listen 82;
        server_name example.com;
        location / {
                proxy_set_header Host '10.20.30.40';
                proxy_pass http://$backendname;
        }
}
server {
        listen 9082;
        server_name default;
        root /var/www/9082;
        try_files $uri $uri/index.html;
}

In my case I needed to write 82 into the map because I can't open the port two times.
You can see another example here.

unNamed
  • 545
  • 2
  • 11