TL Tech Logo
We Solve Your Problems. Seriously, we actually do.
Home
About Us
Services
Stories
Contact Us
Tools
Info Center
  • Sections

    • Code
    • Howto
    • Tips
  • Recent Entries

    • Recovering from a Broken Partition Table
    • RewriteRule in htaccess vs httpd.conf
    • Running PHP through mod_fcgid
    • How They Got Your Password
    • Installing mod_reqtimeout on cPanel
    • Following the Hacker — passwords
    • Using Nginx as a reverse-proxy
    • Dead-simple templates in PHP
    • Tell-a-friend SPAM
    • PHP mail via SMTP

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 or apache2.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 is different 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.

© 2006-2014 TL Tech Services LLC. All rights reserved. Contact us to inquire about republishing rights.