proxy_pass based on (possibly changed) $host

Dave Bailey dave at daveb.net
Wed Jan 28 19:13:05 MSK 2009


Hi Igor,

(response at bottom)

On Wed, Jan 28, 2009 at 7:01 AM, Igor Sysoev <is at rambler-co.ru> wrote:
>> >   map $remote_addr  $back1 {
>> >       default       10.0.0.1:80;
>> >       192.168.1.1   10.0.0.2:80;
>> >       192.168.1.5   10.0.0.2:80;
>> >   }
>> >
>> >   server {
>> >       listen   80;
>> >       server_name   bar.foo.com;
>> >
>> >       location  / {
>> >           proxy_pass  http://$back1$request_uri;
>> >       }
>> >   }
>> >
>> >   map $remote_addr   $back2 {
>> >       default        10.0.0.2:80;
>> >       192.168.10.1   10.0.0.1:80;
>> >       192.168.10.5   10.0.0.1:80;
>> >   }
>> >
>> >   server {
>> >       listen   80;
>> >       server_name   baz.foo.com;
>> >
>> >       location  / {
>> >           proxy_pass  http://$back2$request_uri;
>> >       }
>> >   }

I see, so there is no restriction on the number of server { .. }
blocks that bind to a given port - so the nginx server { .. } is a
name-based virtual host, like with Apache.

>> This is very similar to how i have things set up; but this map is
>> rather static. I "solved" this by using memcached as "map", a simple
>> FastCGI application written in C doing the lookup which returns the
>> backend to use. My question is if this map thing somehow could be
>> expanded to something of a more dynamic nature?
>
> You may write a variable handler in C/ngx_http_perl_module for $back1
> and $back2, but the problem is now variable handlers are blockeing ones.
> There is no way to postpone proxy_pass processing while variable resolution.
>
> So, currently you may only use X-Accel-Redirect:
>
>     location / {
>         fastcgi_pass  ...;
>
>         # it returns
>         # ...
>         # X-Accel-Redirect: /xar"
>         # X-Proxy: http://10.0.0.1:80/some/uri?args
>     }
>
>     location = /xar {
>         internal;
>
>         # you have to store $upstream_http_x_proxy somewhere as it
>         # will be discarded just proxy module will start to work
>         set   $xproxy  $upstream_http_x_proxy;
>
>         proxy_pass   $xproxy;
>     }

Hmm, interesting.  Suppose, then, that my module stores a hash table
that relates the incoming {Host, uri} to the upstream {Host, uri} for
a large number of {Host, uri} keys.  In addition to this mapping, I
would have some "default" location-based mappings in nginx.conf, such
as:

server {
  listen 80;
  server_name bar.foo.com;
  location / {
    proxy_pass http://10.0.0.1:80;
    proxy_set_header Host $http_host;
  }
}

server {
  listen 80;
  server_name baz.foo.com;
  location / {
    proxy_pass http://10.0.0.2:80;
    proxy_set_header Host $http_host;
  }
  location /bar/path/one {
    proxy_pass http://10.0.0.1:80;
    proxy_set_header Host "bar.foo.com";
  }
  ...
}

Suppose that I receive the request:

GET /bar/path/one/of/many/thousands HTTP/1.1
Host: baz.foo.com

In my module, I would look this up in a hash table using the {Host,
uri} as the key.  I might find that the request should be handled
upstream by 10.0.0.1:80 (i.e. the upstream server that contains
bar.foo.com's content) at some completely different URI.  So my goal
is to rewrite the URI and possibly the Host header as a result of what
I find in the hash lookup, and have the proxy module connect to the
correct upstream backend as a result (and retrieve the rewritten URI).

In your config sample, you have:

set $xproxy $upstream_http_x_proxy;
proxy_pass $xproxy;

Within the module's C source code that I write, could I do this
through the ngx_ API, as well as something similar to update the
upstream URI?  There will be too many entries in the hash table for me
to represent it in nginx.conf.

-dave





More information about the nginx mailing list