Friday, April 11, 2014

Using RewriteRule instead of Alias in .htaccess

Subtitle: Why aren't Apache rewrites working?!?!?!?!

I had a few directories (e.g. each a mini website or webapp) sharing a fonts directory, and I was doing this with symlinks. But symlinks are a pain to rsync, so I thought let's use Apache to do the symlinking, i.e. use Alias. I put this in .htaccess:

  Alias /mysite/fonts/ ../shared/fonts/

500 Internal Server Error.

Or, in other words, Alias cannot be used in .htaccess, only in httpd.conf. I could've done it that way (added the Alias to httpd.conf) but as I was already using RewriteRule in the .htaccess file I decided to persevere finding a way to do it using just the .htaccess file.

This was my first attempt:

   RewriteRule ^/mysite/fonts/(.*)$ /shared/fonts/$1  [L]

Completely ignored. Now, when you start googling, or searching on StackOverflow, for "Apache rewrite does not work", 99% of the hits will tell you how to turn it on. I.e. you need AllowOverride All in your httpd.conf, which allows you to use .htaccess files, and you need Options FollowSymLinks so that the rewrite engine will work. And you need RewriteEngine On in your .htaccess file.

Unfortunately I'd done all those things. I knew the rewrite engine was working, as I had other rules in this same .htaccess file, and commenting them out changed behaviour. My problem was that my new rewrite rule was just being ignored, even though it looked correct.

I'll spare you the pain of seeing the 187 other experiments I tried. The forehead-slap moment came when I realized the first parameter of the rewrite rule is relative to the directory the .htaccess file is in. I.e. my .htaccess file is in the /mysite/ directory. And, thus, the correct rule turned out to be:

   RewriteRule ^fonts/(.*)$ /shared/fonts/$1  [L]

Note the lack of leading forward slash. Very important. Incidentally, the second parameter is relative to the server root if you start it with a forward slash! In other words, it is only the first parameter that doesn't work that way.

The [L] at the end of the RewriteRule means "last", and is normally what you want for this kind of rewrite rule. Use [R] ("redirect") instead if you wanted the URL to be rewritten (i.e. an HTTP redirect to be sent back). Useful troubleshooting tip: if you set the flag to [F] then you can immediately see if the first parameter to the rule is being recognized: if it is getting matched, you get a 403 (and if you don't then you have to fix the first parameter). If you get a 403 with an [F], but don't get the expected results when you change the the [F] to an [L] then it is the second parameter you need to fix.

So, to summarize, if your .htaccess file is in a subdirectory, remember that the RewriteRule has to be relative to that subdirectory.

No comments: