Apache, mod_rewrite and Sexy URLs

99% of the people who visit a web site don’t care how it works, or how it was built. They don’t care if you’re using ColdFusion or PHP, and they don’t care if you’re using post or get variables. The remaining one percent comprises some techie types like me, and probably you, and some people with less than honourable intentions. For members of the latter group, you don’t WANT them to know what type of technology you use.

This is a good argument for URL rewriting, as is the fact that semantic and descriptive URLs assist in search engine ranking, and general usability. I rewriting my URLs because I like the way they look. I think a website looks much more polished when the URLs are descriptive, free of variable/value pairs, and as short possible.

Since I tend to use Apache with most of the sites I work on, and I recommend you do the same wherever possible, I’m only going to talk about using mod_rewrite, an almost universal Apache module for URL rewriting. There are similar solutions available for other web servers. I’ll show you an example use of mod_rewrite for a skeleton example site. I’ll provide all the code as well so you can play around with a working example. Please remember that this is just a quick overview of the mod_rewrite functions, and how they can be used with ColdFusion. It is always a good idea to lock down your Apache install as much as possible for public sites, and it should also be noted that using mod_rewrite does involve a small performance hit.

Turn on mod_rewrite

You may already have the mod_rewrite module activated in Apache. It’s simple to check. You need to be familiar with editing the httpd.conf file for your Apache install.

Make sure the following line in your httpd.conf file is NOT commented out (it commented out by default).

LoadModule rewrite_module libexec/apache2/mod_rewrite.so

Another thing you need to be sure of is that the AllowOverride directive is turned on for your web root.  The default settings in apache is “none”.  This needs to be changed to “all” to enable the .htaccess file to change Apache settings. This can be found either in the default section it can be set on a per directory basis.

    Options FollowSymLinks
    AllowOverride All
    Order deny,allow
    Deny from all

If you need to make a change, remember to stop and restart Apache for your changes to take effect.

Looking at the Rewrite Directives

Here’s my example .htaccess file. This file goes in your web root. I’ll go through it step by step in a minute. One important prerequisite for understanding the mod_rewrite file is that you will need to have a good understanding of regular expressions in order to write your own rules.

RewriteEngine on

RewriteRule ^$ app/index.cfm [L]
RewriteRule ^(contact|about|blog|categories)/?$ app/$1.cfm [L]
RewriteRule ^demos/([0-9]*)/?$ app/content/demo$1/index.cfm [L]
RewriteRule ^c/([a-zA-Z0-9\-\_]{1,30})/?$ app/categories.cfm?cat=$1 [L]
RewriteRule ^([a-zA-Z0-9\-\_]{1,30})/?$ app/post.cfm?key=$1 [L]

RewriteCond %{HTTP_USER_AGENT} MSIE\s(\d)\.(?!.*Opera)
RewriteCond %1 <=6
RewriteRule ^(/[a-zA-Z0-9\-\_\.])*assets/css/main\.css$ css/main-ie.css [L]

RewriteRule ^(/[a-zA-Z0-9\-\_\.])*assets/js/jquery\.js$ js/jquery/jquery-1.3.2.min.js [L]
RewriteRule ^(/[a-zA-Z0-9\-\_\.])*assets/css/main\.css$ css/main.css [L]

Line 1 is important, as it activates the Rewrite engine.

The rewriting starts on line 3. I like to keep my main site files in a folder called “app” in my web root, so the first line rewrites a call to the web root to “/app/index.cfm”

Line 4 redirects a few of the regular top-level pages in the site to their respective locations in my directory structure. /contact to /app/contact.cfm, /about to app/about.cfm, etc.

Line 5 redirects links to demos I included on the site. /demo/1 goes to /app/demo1/index.cfm, /demo/2 goes to /app/demo2/index.cfm, and so on.

Line 6 is for the categories pages for the blog that is part of the site. For example, the link /c/cars would get redirected to /app/categories.cfm?cat=cars.

Line 7 will take any remaining link that does not contain a “sub-directory” and assumes it is a blog post. The links would be forwarded like this: /apache-url-forwarding would be rewritten as /app/post.cfm?key=apache-url-forwarding. This allows you to use the key to lookup a blog post and display it for the reader. These short titles are usually called “slugs” by blogging software and are unique titles given to your posts for use in search engine friendly URLs.

Line 9 and 10 are conditional, and serve the purpose of rewriting the CSS file differently for Internet Explorer 6 and below than it is for the rest of the browsers. You can see that line 11 directs calls to the main CSS file to an IE6 specific file. The preceding rewrite conditions apply to the rewrite rule that immediately follows the condition.

Line 13 rewrites the CSS file for the remaining browsers. You may wonder why I bother rewriting the URL of the CSS file. I like to keep several sets of CSS files on hand – sometimes different themes, sometimes different versions, and sometimes just a specific set of CSS files for development only. Rewriting the CSS URLs allows me to switch between the files with ease without touching my application code at all.

Line 14 rewrites the call to an external JavaScript file – in this case jQuery. This is helpful for managing versions of a jQuery library. In this case, I’m just calling a file called jquery.js, but I’m linking to a minified version of jquery 1.3.2.

The Code

I’ve gone through this pretty quickly, and without a ton of detail, but I’ve included the code all zipped up nicely for you to try it yourself. Stick the whole directory structure in your development web root, and give it a try. Remember to turn on mod_rewrite.

Zipped Up Files