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.
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
This
post was originally published at http://tltech.com/info/rewriterule-in-htaccess-vs-httpd-conf/.
Special Thanks
to TL Tech Services
LLC for allowing me to republish it on my blog.