Apache - RewriteRule in htaccess vs httpd.conf

Typically Apache’s RewriteRule sets from mod_rewrite go in .htaccess files, but sometimes you have a good reason to put them in your general server config instead:

your httpd.conf orapache2.conf file (or a file you Include from one of those). If you’ve done this before, you’ve probably been surprised that it didn’t work quite the same.
So while this works in .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /index.php [L]
Putting the same thing in your VirtualHost doesn’t work at all:
<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/example/
    <Directory /var/www/example/>
        Allow From All
    </Directory>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule . /index.php [L]
</VirtualHost>

Apache doesn’t tell you why it doesn’t work. It just doesn’t work. You most likely will get an Error 500 status with a message in the logs that looks like this:

Request exceeded the limit of 10 internal redirects due to probable configuration error. Use ‘LimitInternalRecursion’ to increase the limit if necessary. Use ‘LogLevel debug’ to get a backtrace.

Getting Some Context
So what went wrong? At issue here is the context of the matching that the RewriteRules do. This is all spelled out in the mod_rewrite documentation, but you have to know where to look:

What is matched?
In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. “/app1/index.html”).
In Directory and htaccess context, the Pattern will initially be matched against the filesystem path, after removing the prefix that led the server to the current RewriteRule (e.g. “app1/index.html” or “index.html” depending on where the directives are defined).
In other words, Apache matches different things depending on whether the RewriteRule or RewriteCond directive is placed inside a <Directory> block. And significantly, everything in an.htaccess file is assumed to be in Directory context.

So rules in a .htaccess file behave the same way as rules in a <Directory> block, which isdifferent from the way rules behave outside a <Directory> block. Armed with this knowledge, we can fix our httpd.conf file just by moving the rules into the <Directory> block:

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/example/
    <Directory /var/www/example/>
        Allow From All
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule . /index.php [L]
    </Directory>
</VirtualHost>

And you’re done! It really is that simple.
Well, mostly that simple. If your .htaccess file is not in the base of your Document Root, then the path prefix is removed before matching. You may want to read that documentation page a bit more closely if you’re doing that.

THANKS TO
Special Thanks to TL Tech Services LLC for allowing me to republish it on my blog.