How I Slayed mod_rewrite In 4 Days

I just spent the last 4 days figuring out mod_rewrite.

My journey began reading through the cryptic documentation located on apache's website[1]. It doesn't really describe what is necessary, but it is somewhat clear that in order to do anything useful or interesting, you'll need to learn how RewriteCond and RewriteRule work. RewriteCond has an interesting syntax for mod_rewrite variables. It uses a variation of the ${} syntax, that BASH, PHP, and Python all use. It decides to be special, and use %{}. I wasted a couple hours debugging simple mod_rewrite scripts in my .htaccess file in order to figure out why nothing was working as described. Only a single person in #httpd on freenode caught my error of using ${} instead of %{}. Gah.

The fun doesn't stop there though! In order to write mod_rewrite rules, you really have to understand the inner workings of the module. After hours of reading solutions to problems that seemed so simple but gave no explanations, one finally helped. It turns out that mod_rewrite actually loops over rules until no rules are satisfied. This is not specified on the apache site. So I added RewriteConds that would stop the infinite looping. Still no desired functionality. Next I wanted to check out the log files to see what was happening. I read the documentation to enable logging for mod_rewrite...only to find out an hour later, I was using an old syntax that no longer worked. After using the correct syntax and checking out the logs, I was baffled. My URL was being rewritten, but then it was being rewritten AGAIN! Even after I used a condition that says for mod_rewrite to explicitly stop after one redirect. I spent many more hours trying to guess what was going on by modifying my rules.

At first I knew it had to do with apache searching for a default file. I wasn't explicitly requesting files with URLs, just paths. I could see mod_rewrite/apache cycling through the files in the log output, and I could also see my INTERNAL REDIRECT happening, but not actually working whatsoever! I was baffled. At this point I thought I was finished. Apache must completely ignore rewrite rules when searching for a default file. After some experiments that didn't seem to be entirely the case, as the INTERAL REDIRECT message would appear. So what was going on?...

After hours of research, fiddling, and asking for advice in #httpd I thought I was absolutely done for. People were saying to remove options from virtual host configurations like MultiViews and to try adding more RewriteConds in the .htaccess file and to stand on your head and restart apache2 whilst drinking RedBull. None of it worked of course, but I was desperate. Then suddenly by the will of God, I found an answer[2]. I had encountered an obscure bug[3] in Apache 2.4. The problem? mod_rewrite acts different when using rules in an .htaccess file, and in other places. That's right, mod_rewrite throws consistency out the window! Because why not!! Ok it's not mod_rewrites fault entirely- another module, mod_dir, "is not respecting the result of the rewrite execution". A work around for this is to move the rules from the root .htaccess file to the virtual host configuration, and every, single, thing, worked. Everything as expected days before. The entire time I was doing every single thing right. After days of work I had slain the mod_rewrite beast, lived to code another day, and had become a mod_rewrite warlock.

It is highly recommended to read this[4] when diving into any mod_rewrite programming.

Please tell people about your mod_rewrite battles so others will never have to go through the horror again.



Popular Posts