How to set up an Apache 2 reverse proxy with dynamic backend servers

apache-2.2reverse-proxy

I would like to set up Apache 2 as a reverse proxy using name-based virtual hosts to decide how requests are routed to back-end servers. Simple enough.

The catch is that these back-end servers may be added and removed in a dynamic fashion. My first idea was to programmatically re-write an Apache configuration file and call apachectl graceful every time a back-end server goes up or down. This does not seem like the correct solution. What is a better way to accomplish this?

I need to be able to gracefully transfer handling of names over to different back-end servers. For instance, Backend-Server-A might be handling requests for example.com. A monitoring process might decide that Backend-Server-A is stale (too much memory usage, there's new version of the server code to handle example.com, etc). The monitoring process starts Backend-Server-B which will soon handle requests for example.com. Apache should direct any new requests for example.com to Backend-Server-B, but allow any pending requests currently being handled by Backend-Server-A to complete before Backend-Server-A is shut down by my monitoring process.

(Note: I originally posted this on Stack Overflow.)

Best Answer

The only thing that comes to mind is to use a RewriteMap script which will decide which machine to go to, via the P flag to RewriteRule, something like

#!/usr/bin/perl
#This is /usr/bin/requestdistributor.pl
$| = 1; # Turn off buffering
while (<STDIN>) {
        print distributeRequest($_);
}
sub distributeRequest {
    my $request = shift;
    #do whatever you have to do to find the proper machine for the request,
    #return the complete URL with a trailing newline
}

Then in the Apache configuration file

RewriteMap distributeRequests prg:/usr/bin/requestdistributor.pl 
RewriteRule (.*) ${distributeRequests:$1} [P]

#Setup the reverse proxying for all machines, use the proper URLs
ProxyPassReverse / http://machine1
ProxyPassReverse / http://machine2
#and so on...
ProxyPassReverse / http://machineN

Caveats: This might have some flaws as it's untested, you would have to add a new ProxyPassReverse when you add a new server (and do a graceful), and, now that I think about it, depending on the specifics of the applications you might not even need the ProxyPassReverse lines. So, test this and please tell us if it worked (or not).