RewriteMap not working, nothing is rewritten (Apache 2.4)

apache-2.4mod-rewriterewriterewritemap

I have a bit of a unique situation: I need to take a subdomain and make it redirect to a random selection of alternate domains, each of which is on a separate server. Think load balancing, except it's technically different from that.

Upon investigating my options, Apache's RewriteMap seemed like the ideal solution, except I can't seem to get it to do anything at all. Here's what I've got so far:

In my configuration file, I've added:

RewriteMap map "rnd:/home/mydomain/public_html/servers.txt"

This is in the server context, not VirtualHost or Directory. However, I do have "AllowOverride All" set for the public_html directory. And yes, I did remember to restart Apache after saving changes to my config.

Next, the servers.txt file itself:

servers domain1.com|domain2.com|domain3.com

(It doesn't really matter if these domains are exposed to the user, hence I'm just putting this in public_html for now, but I may move it elsewhere if I can get it working.)

Finally, I have an .htaccess file in public_html which already has several working Rewrite conditions and rules. RewriteEngine is on and all that. But when I add…

RewriteCond %{HTTP_HOST} ^subdomain.domain.com$
RewriteRule ^(.*)$ "https://${map:servers}/$1" [P,L]

… visiting my subdomain just shows the subdomain itself. I've tried a variety of different flags, but to no avail. At best, if I replace the [P] flag with [R=301] I can get a ERR_INVALID_REDIRECT response from the browser, which tells me the rule is at least being processed. Other than that, I don't even get any errors in Apache's error_log file. I've also made sure no other rules have the [L] flag, which might cause the new rule to be skipped.

As far as I can tell, according to the Apache documentation this is exactly the way RewriteMap is supposed to be used, so I'm a little perplexed to say the least. Can anyone tell me what I'm missing here?

Best Answer

I've also made sure no other rules have the [L] flag

That raises alarm bells. It perhaps implies you've put these directives in the wrong place in your .htaccess file. Your "redirect" should go near the top of your .htaccess file. (I would expect most RewriteRule directives to require the L flag and at the very least for optimisation.)

mod_rewrite directives naturally chain together - in that the output of the previous is the input of the next and so on. If you've removed the L flags from preceding directives and placed your redirect later in the file then your $1 backreference is not capturing the requested URL, but the rewritten URL from any preceding directives.

You should be able to see the URL that triggers the ERR_INVALID_REDIRECT in the browser by monitoring the network traffic (in the browser tools).

if I replace the [P] flag with [R=301]

The P flag sends the request through mod_proxy (as a reverse proxy - which requires additional config). If you want to externally redirect the request then you should use the R flag.