5

I'm trying to figure out the best way to handle dynamic proxying of HTTP requests.

Basically I want to take a dynamic hostname in the form of myname.cust.mydomain.example and then forward requests to an HTTP backend server with the name "myname" taken from the hostname.

I've been racking my brain trying to figure out the best way to handle this and if HAProxy is even up to the task.

Another option I was thinking was something like Lighttpd with LUA or even Nginx.

Patrick Mevzek
  • 9,273
  • 7
  • 29
  • 42
Jez
  • 59
  • 1
  • 3
  • How would you go about mapping `myname` to a particular backend server? – womble Jul 19 '11 at 06:26
  • That's what i'm trying to do. Myname will be an internal server that I want to proxy requests to, so that if a user visit Myname.cust.mydomain.com it will automatically proxy the request through to Myname on the internal network. There may be a few hundred servers, and ideally it should be dynamic. – Jez Jul 19 '11 at 12:45

1 Answers1

12

The easiest solution would be just use DNS to map foo.cust.mydomain.example to a specific server IP, as womble suggested. This would skip the entire proxy server. Perhaps this is not possible for you, for example if you do not have public IP addresses for the backend servers.

Directing all requests to one server (with a wildcard DNS) and then forwarding the requests dynamically according to the Host header is a bit more complicated, and it seems HAProxy cannot do this, because every backend server must be explicitly defined in HAProxy configuration.

Nginx, though, is different, with right configuration Nginx can use Host header to choose the backend. Nginx needs a DNS server that maps names to backend addresses, of course.

Here is a small example of the configuration:

server {
    listen 80 default;

    location / {
        # You might need to send some headers to the backend server
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;

        resolver 192.0.2.1; # DNS server IP
        # Forward all requests to the backend server using $http_host
        # (this is the 'Host:' header value)
        proxy_pass http://$http_host$request_uri;
    }
}

This redirects http://myserver.cust.mydomain.example/foo/ to http://myserver.cust.mydomain.example/foo/. Does not seem very helpful at first sight. But if you set up a private DNS server that maps those names to a backend server addresses, the request actually gets forwarded to a correct backend server on a private address.

But, this kind of DNS server setting might not be desired, and could cause problems in some cases. So, with some additions to the Nginx config, we can take another approach:

location / {
    # headers...

    resolver 192.0.2.1;

    # A regex to get the first part (hostname) from the Host header
    if ($http_host ~* "([a-z0-9-]+)(\.[a-z0-9-]+)*") {
        # Save a captured part from the regex to a variable
        set $redirect_hostname $1;
        # Pass the request to a desired backend
        proxy_pass   http://$redirect_hostname.private.mydomain.example$request_uri;
    }
}

Now redirect goes from http://myserver.cust.mydomain.example/foo/ to http://myserver.private.mydomain.example/foo/. The DNS server can hold private addresses under different domain, and proxy_pass directive can be modified to match the desired name server configuration.

I still think this kind of proxying might not be the easiest way to solve the whole picture, but it's one possibility after all. I'm happy if this was of any help.

References: Nginx Wiki, especially HttpProxyModule and HttpRewriteModule

Patrick Mevzek
  • 9,273
  • 7
  • 29
  • 42
Mikko
  • 955
  • 8
  • 14