6

I want to use Nginx in a bit of an unconventional way. I want to load balance between a few servers, but rather than proxy content for those servers I want to redirect to them.

That is, if a request comes into my Nginx server, it should 302 redirect to another server by randomly picking one out of an upstream block or equivalent. I don't even need the other upstream block features, such as weighting (but it wouldn't hurt to have them available if possible).

For now, I have the following config, which does what I need but is a bit ugly:

upstream boxes {
        server 127.0.0.1:46011;
        server 127.0.0.1:46012;
}

server {
        listen 46011;
        return 302 http://box11.example.com$request_uri;
}

server {
        listen 46012;
        return 302 http://box12.example.com$request_uri;
}

server {
        listen 80;
        server_name example.com;

        location / {
                proxy_pass http://boxes;
        }
}

Is there a simpler way to handle this situation without resorting to proxying to myself?

shgnInc
  • 1,804
  • 3
  • 22
  • 29
Brad
  • 1,419
  • 22
  • 43
  • Your problem is similar to mine [here](http://serverfault.com/questions/829477/nginx-multiple-server-instances-502-when-proxy-pass) – pier92 Jan 30 '17 at 16:30
  • What advantages are you getting by using redirect instead of proxy? You lose many features like security, compression, anonymity, etc – Jasper Wu Feb 20 '22 at 20:59
  • @JasperWu Consider load balancing between multiple CDNs with different hostnames, for example. – Brad Feb 20 '22 at 22:43

1 Answers1

5

You can get a random variable from misc module:

set_random $loc_rnd 1 10;

Then choose internal location based on it, with simple weighting:

map $loc_rnd $loc_redirect {
  1 @server1;
  2 @server1;
  ...
  8 @server2;
  9 @server2;
 10 @server2;
}

location / {
 recursive_error_pages on;
 error_page 403 = $loc_redirect;
 return 403;
}

Redirects:

location @server1 {
  internal;
  return 302 http://box11.example.com$request_uri;
}

location @server2 {
  internal;
  return 302 http://box11.example.com$request_uri;
}

Other variant: use return 302 $some_variable; (and full URLs in map) directly in "/" location.

kupson
  • 3,578
  • 20
  • 19
  • Gross, why do you need to return an internal "forbidden" to get a random redirect? – meawoppl Jan 26 '16 at 01:03
  • 1
    You can use any return code in 4xx range. Nowadays I tend to use 412. Jumping around with error_page+return have far less surprising effects than location+if solution. – kupson Jan 26 '16 at 07:51