Sunday, June 3, 2012

mod_rewrite rule to redirect all requests except for one specific path

I'm trying to redirect all requests to my domain to another domain using mod_rewrite in an Apache 2.2 VirtualHost declaration. There is one exception to this -- I'd like all requests to the /audio path not to be redirected.

I've written a RewriteCond and RewriteRule to do this but it's not quite right and I can't figure out why. The regular expression contains a negative lookahead for the string "/audio", but for some reason this isn't matching. Here's the definition:

RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*\.)?mydomain\.net(?!/audio) [NC]
RewriteRule ^(.*)$ [L,R=301]

If I change the RewriteCond to:

RewriteCond %{HTTP_HOST} ^(.*\.)?mydomain\.net/(?!audio) [NC]

(i.e. put the forward slash outside of the negative lookahead part) then it works, but the downside of this is that requests to without a trailing slash will not be redirected.

Can anyone point out what I'm doing wrong?

(Note: the angle brackets around the domain in the RewriteRule bit above are being added by -- they are not there in the actual code!)

Here are the rules:

<VirtualHost *:80>
DocumentRoot "/var/www/"

RewriteEngine on
RewriteCond {REQUEST_URI} !^/audio
RewriteRule ^(.*)$ [L,R=301]
RewriteLog logs/mod_rewrite_log
RewriteLogLevel 3

ErrorLog logs/error_log
CustomLog logs/access_log common

Thanks @mercutio -- that makes perfect sense but it still doesn't seem to work.

Here's what the mod_rewrite log says when I make a request to :

(2) init rewrite engine with requested uri /audio/something.mp3
(3) applying pattern '^(.*)$' to uri '/audio'
(2) rewrite '/audio' -> ''
(2) explicitly forcing redirect with
(1) escaping for redirect
(1) redirect to [REDIRECT/301]

Since the REQUEST_URI does start with /audio I would expect the RewriteRule to be ignored.

Source: Tips4all


  1. RewriteCond {REQUEST_URI} !^/audio

    Should be:

    RewriteCond %{REQUEST_URI} !^/audio

    My bad!

  2. The HTTP_HOST only contains the host name, not the path of the url requested.

    RewriteCond {REQUEST_URI} !^/audio

    Should be all you need.

    Further, you can get debug info from the rewrite engine with the following, which is really useful to see how your conditions and rules are being matched:

    RewriteLog /path/to/log/file
    RewriteLogLevel 3

  3. applying pattern '^(.*)$' to uri '/audio'

    Sounds like it's processing a different pattern. Or perhaps the logic is just backwards now. Can you post your full set of rules?