Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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.)

share|improve this question

3 Answers 3

up vote 3 down vote accepted

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).

share|improve this answer
    
Didn't previously know about the RewriteMap directive; I will look into it. However I would like to avoid modifying the config file and/or restarting Apache if possible. Thanks –  user24338 Oct 29 '09 at 7:00
    
Two things: I'm not sure it would be required and in case it's required it would only be required when you'll add new machines to the set of proxied machines, so that shouldn't be such a burden, machines going up or down do not matter –  Vinko Vrsalovic Oct 29 '09 at 7:14
    
I see. Yes, looks like Apache would need to be restarted for adding a new host (for instance, example2.com) or new back-end server/process. But luckily not for the most common case of recycling or updating processes. Thanks! This is a very handy directive! –  user24338 Oct 29 '09 at 8:31

This should really be a comment to the "RewriteMap" script but apparently I am a bit "pointless" for commenting...

If your using a newish verison of Apache, Vinko's suggestion can be implemented using the "dbd" option to RewriteMap and mod_dbd to query a simple sqlite3 database and manage the lookup 'in process'.

Nothing beats an in memory lookup though, I've used auto graceful reconfigures on live services and it works quite well but I guess it's a question of your graceful restart frequency and the impact during your apache startup time. The main thing we had to avoid was having anything based on DNS lookups (e.g vhost configs using domains) as it was possible for the dns lookup timeouts to cause delay and the incoming queue's to fill up and an outage rather than a brief pause.

As always, load test a couple of solutions to see what the difference's are.

share|improve this answer
    
Note for those who end up here from Google: Apache does not fork a new process for every request. The prg program is started once, when Apache starts up, and communicates via a stream of requests/resposnes on stdin/stdout. You can read more in the documentation. –  larsks Aug 24 '12 at 12:56
    
thanks for the info –  mtm Aug 25 '12 at 8:10

There are better tools for this, varnish is an excellent reverse proxy that can handle backend health check, fail-over, load balancing etc. You can find the relevant documentation here and here.

share|improve this answer
    
Unfortunately it has to be Apache. –  user24338 Oct 29 '09 at 6:55
    
Ok, then I +1 for Vinko's answer... –  rkthkr Oct 29 '09 at 8:05

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.