Posts Tagged ‘.htaccess’

How to move the site root to a subdirectory on cPanel-based web hosts

Sunday, November 15th, 2009

I’m going to start off by saying that I’m rather picky about how files and folders are organized on a computer. For my own site structure, I’ve placed each subdomain into its own directory. Many hosts using cPanel (like BlueHost and HostMonster) allow you to set the directory where the subdomain’s files can be placed. However, it is not immediately obvious how you can accomplish the same with the root domain. By default it is mapped to the /www (/public_html) folder and there are no options in cPanel that allow you to change this. Good thing there’s an alternative solution. :)

For this to work, you must be running Apache as your web server (I suppose IIS should have a similar method, but eh…) and have mod_rewrite enabled. We’ll be creating (or adding to) a .htaccess file as follows:

1
2
3
4
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?domain.com$
RewriteCond %{REQUEST_URI} !^/subdir/
RewriteRule ^(.*)$ /subdir/$1

The first line turns the runtime rewriting engine on to allow for modifications. The second line determines whether the request came from “www.domain.com” or “domain.com”; this is to prevent rewriting the URLs of any subdomains you might have. The condition after checks to see whether the request has already been redirected to the subdirectory. If not, then the rewriting rule is executed to make it so.

The above code is sufficient if all you want is to move files from “/www/” to a subdirectory “/www/subdir/”. However, Apache is quirky in that it requires a trailing slash at the end of directory names (to specify that it is indeed a directory). Normally this isn’t a problem since there is a module (mod_dir) that automagically redirects a path without a trailing slash to one that does. However, it conflicts with the above code in this case: first a request is directed to a subdirectory and then mod_dir issues another redirect, exposing the subdirectory name. For example, a request for “http://irythia.com/somefolderhere” will become “http://irythia.com/subdir/somefolderhere/”.

Note: mod_dir only executes if there isn’t a trailing slash on directory names, so if you qualify URLs with one the rules above work as expected. That is, “http://irythia.com/somefolderhere/” won’t change.

To fix this problem, we add another rule to append a trailing slash on all URLs ending in directory names.

1
2
3
4
5
6
7
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?domain.com$
RewriteCond %{REQUEST_URI} !(/|\.[^/]*)$
RewriteRule (.*) http://www.domain.com/$1/ [L,R=301]
RewriteCond %{HTTP_HOST} ^(www\.)?domain.com$
RewriteCond %{REQUEST_URI} !^/subdir/
RewriteRule ^(.*)$ /subdir/$1

Note the additions in lines 2-4. Again, line 2 checks to see whether the request came from “www.domain.com” or “domain.com”. Line 3 checks to see if the URI ends in a directory by filtering out file extensions (i.e. .php, .html, .js, .css, etc.). It also checks to see if there isn’t already a trailing slash. Finally, we rewrite the URL. The [L,R=301] flag tells Apache to not execute any more rules and do a permanent redirect.

And that’s that. Upload the .htaccess file to the root web directory (/www or /public_html) and you’re good to go.

Some final notes: this is essentially a hack to work around limitations imposed by many web hosts; there are probably better methods if you have direct access to the server. Since it is a hack, it might not work on all sites without modification; this post is pretty much a reference for myself. As well, there is likely some performance penalty (as minor as it is) because the .htaccess file rewrites all requests that hit the domain. Of course, if you were that worried about performance, you wouldn’t be running on a shared host anyway. :P