Nginx reverse proxy with dynamic port forwarding
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...
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.