Skip to content
 

mod_rewrite with a Dynamic RewriteMap

Apache’s mod_rewrite is a beast.  The opening lines of documentation admits it before you even get started.  It’s very powerful, but sometimes hard to wrap your head around what’s going on.

Today I needed to dynamically point a request to a folder depending on what the %{SERVER_NAME} is. After reading a bit of documentation, I’ve found a slick little solution.

Let me give a little more info about this setup before I get started…

I’ve got a web application that serves multiple sites.  If you point your domain to the app’s IP address it will do a lookup on the server name to determine if that site exists in the app.  If so, it serves the site.  If not, it tells you to go away!  Any request for www.example.com – from any or no subdomain – should check to see if example.com is a valid domain. I don’t care if someone points wiki.example.com, www2.example.com, or just example.com to my app’s IP – I am only looking for example.com in my valid sites list.

All of the code for this app belongs in one common directory, but what about site specific (user uploaded) files?  They need to be in a separate location but still easily referenced from some common fake directory (relative to web root) such as “/files”.

There are a number of ways to handle this, but I wanted apache to do the work for me.  I’m already using mod_rewrite to route all requests through a single controller, so I can just add another rule to point requests to static files where they should go.

Lets say a request comes in for http://example.com/files/headshot.jpg.  I really want to view %{DOCUMENT_ROOT}/userfiles/example.com/headshot.jpg.  That’s pretty simple:

RewriteRule ^/files/(.*) /userfiles/%{SERVER_NAME}/headshot.jpg

But what happens when a request for http://www.example.com/files/headshot.jpg?  The rule above will try to look in /userfiles/www.example.com/headshot.jpg.  That folder doesn’t exist, so we’ll get a 404.

We need to convert www.example.com to example.com.  Sadly, there are only a few internal functions in Apache and you can’t define your own, so we need to use a RewriteMap.  The most basic RewriteMap would be a plain text file of key-to-value lines.  But in this case we don’t know how which domain is being requested, let alone which subdomain might be present.  It’s a little too hairy for a standard txt rewrite map, so we’ll use an external program.  This code evolves from the documentation on apache’s website.

#!/usr/bin/perl
$| = 1;
while () {
    my @parts = split('\.', $_);
    print @parts[-2] . '.' . @parts[-1];
}

This file, which I’m calling domainfix.pl, will serve as our dynamic rewrite map.  Don’t forget to give apache (or the user that starts apache) execute permissions for this file otherwise it won’t work!

Now we add the RewriteMap line to go along with a sliightly modified version of our previous rule:

RewriteMap          domainfix  prg:/etc/httpd/conf.d/domainfix.pl
RewriteRule         ^/files/(.*) /userfiles/${domainfix:%{SERVER_NAME}}/$1 [NC,L]

And that’s it!  After I figured out what exactly it is I’m doing here it was much easier to search for similar notes on doing this kind of thing, but hopefully this will expand Google’s hits for those who are struggling.

2 Comments

  1. Alex says:

    Your blog is interesting!

    Keep up the good work!

  2. chips zynga says:

    eventhough I waste the majority of of my night on the web actively playing online games like zynga poker or petville, I always like to take some time to research a a small number of information sites now and then and I’m content to report this latest content is in actual fact more than a little effective and quite more beneficial than half the other spam I read today , anyways i’m off to enjoy a couple of hands of facebook poker

Leave a Reply