Web hosting with Apache VirtualHosts

by Marion Bates <mbates at whoopis.com>
with much help from William Stearns <wstearns at pobox.com>

NOTE: If you want to know how to set up Apache's auth/.htacess stuff (i.e., to make parts of your website(s) require users to log in before they can view certain pages), please see this howto.

If you have registered multiple domains, and you want to serve webpages for each of them from your single server, you can achieve this through the use of the VirtualHosts directive in /etc/httpd/conf/httpd.conf. Scroll down until you find the Virtual Hosts section, and edit it accordingly, using the following as a template:

### Section 3: Virtual Hosts
#<snip>
# ...
# Use name-based virtual hosting.
#
NameVirtualHost *

#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for requests without a known
# server name.
#
#<VirtualHost *>
#    ServerAdmin webmaster@dummy-host.example.com
#    DocumentRoot /www/docs/dummy-host.example.com
#    ServerName dummy-host.example.com
#    ErrorLog logs/dummy-host.example.com-error_log
#    CustomLog logs/dummy-host.example.com-access_log common
#</VirtualHost>

# www.yourfirstdomain.com
<VirtualHost *>
        ServerAdmin your-email@whatever.com
        DocumentRoot /home/www.yourfirstdomain.com/html
        ServerName www.yourfirstdomain.com
        ScriptAlias /cgi-bin/ /home/www.yourfirstdomain.com/cgi-bin/
        ErrorLog logs/www.yourfirstdomain.com-error_log
        TransferLog logs/www.yourfirstdomain.com-access_log
        <Directory /home/www.yourfirstdomain.com/html>
                Options Indexes FollowSymLinks
        </Directory>
</VirtualHost>

# www.yourseconddomain.com
<VirtualHost *>
        ServerAdmin your-email@whatever.com
        DocumentRoot /home/www.yourseconddomain.com/html
        ServerName www.yourseconddomain.com
        ScriptAlias /cgi-bin/ /home/www.yourseconddomain.com/cgi-bin/
        ErrorLog logs/www.yourseconddomain.com-error_log
        TransferLog logs/www.yourseconddomain.com-access_log
        <Directory /home/www.yourseconddomain.com/html>
                Options Indexes FollowSymLinks
        </Directory>
</VirtualHost>

Create appropriate directories for each website's HTML, cgi, etc. and restart httpd. Assuming the example above, if a user enters "http://www.yourfirstdomain.com/" into his browser, he will receive the index.html (if it exists) that resides in /home/www.yourfirstdomain.com/html/. If he enters "http://www.yourseconddomain.com/" into the browser, he'll get that domain's index.html file instead. Apache will hand off the appropriate set of HTML files based on the name it gets from the user.

An interesting quirk occurs with this setup, and there is an easy fix. For the sake of example, let's assume you are hosting two virtual domains, like the following (irrelevant lines chopped):

# www.foo.com
<VirtualHost *>
        ServerAdmin your-email@whatever.com
        DocumentRoot /home/www.foo.com/html
        ServerName www.foo.com
        ...
</VirtualHost>

# www.bar.com
<VirtualHost *>
        ServerAdmin your-email@whatever.com
        DocumentRoot /home/www.bar.com/html
        ServerName www.bar.com
        ...
</VirtualHost>

Users type http://www.foo.com or http://www.bar.com, and they get index.html from the right place depending. And if users type http://foo.com (no "www") then they will get the pages for foo.com. BUT if users type http://bar.com, they will get FOO's pages. Why? It has to do with the way the webserver responds to a hostname request -- users will always get the webpages for the first (default) virtual domain in your conf file.

The fix is to add a ServerAlias line in each block, like so (note that this assumes a DNS setup like the one shown above -- you have to have already defined "domain.com" there before this will work):

# www.foo.com
<VirtualHost *>
        ServerAdmin your-email@whatever.com
        DocumentRoot /home/www.foo.com/html
        ServerName www.foo.com
        ServerAlias foo.com
        ...
</VirtualHost>

# www.bar.com
<VirtualHost *>
        ServerAdmin your-email@whatever.com
        DocumentRoot /home/www.bar.com/html
        ServerName www.bar.com
        ServerAlias bar.com
        ...
</VirtualHost>

Don't forget to restart httpd after making this change.

If you enable public_html directories for the users on your server, they will, under this setup, be accessible via "http://www.yourfirstdomain.com/~username/" AND via "http://www.yourseconddomain.com/~username/". There is probably a way around that, but I didn't care. :)

The httpd.conf file comments explain the requisite permissions for user html directories to work. Each user's home dir must be mode 711, and their public_html dirs must be mode 755.