Part 5: Setting-up a Linux Development Machine: Virtual Hosts in Apache2

When I am working on code project, I isolate that project within it's own directory/repository.  Further, it matters not if I'm starting a completely new project, or if I'm branching off the trunk of an existing project.  As a means of imposing order over chaos, I isolate the existing project within it's own sandbox both on the filesystem and via Apache2.

To do so requires an understanding, somewhat, of the mechanics of Apache2, DNS, and your localhost.  A minimal understanding, trust me.

What it, in return, gives you is an isolated view of your code project from the web-server perspective.  Cookies are isolated by domain, your document root is isolated to a single directory/repository, and you not only put your log files, just for that domain, where ever you want but you can also name them anything you want as well.

What I'll provide you with in this installment is a rudimentary understanding of the mechanics behind virtual hosting using Apache2, a template configuration file to get you going, and the basic steps necessary to get the whole mess working.  Let's get started...

When you start a new project, if you're checking it out from a source-code repository, you'll typically assign it to a directory somewhere common.  For example, within your home directory, you may have a folder named "code" and beneath that folder, other folders that describe either the project or the programming language you're working in.  Doesn't really matter as the point is this:  you've isolated your code repository from everything else on your filesystem, right?

It really doesn't matter, to Apache2, where you create your filesystem repository.  As long as the webserver pseudo-user has access permissions to the directory, then you can access the files within that directory via a web browser.  The webserver has to be configured to be told that, for a given domain name, where is the documentRoot for that domain.

Some of you, at this point, may be asking: what's a domain name and why is it important?  Well, a domain name is simply a name you've assigned to the project to keep it separate, at least in your own head, from the other projects you may, or may not, have running on your development machine.  For example, I create a new project called newWidget and it's currently in the 1.4 revision.  I'm ready to branch and write some new features for the product so, using whatever sccs tool, I branch off the trunk and create the 1.5 branch.

I check that branch out to a directory in /lampdev/php/newWidget115.  I now need to do two basic things:

  1. invent some domain name that will be used exclusively for this project and resolve the domain to my localhost
  2. create a virtual host in apache so that apache knows that http://newW115 points to my localhost

The reasons, apart from what we've already discussed, is to keep your local DNS services on your local machine.  If you, before entering any configuration information, entered: http://newW115 into a browser url bar, chances are very good you're going to end-up on a search page (I'm using Chrome) or get some sort of browser error.

So the first step is to define the new domain name (again, given that we're already checked the code out into the aforementioned directory) to the local system so that all requests to that domain are resolved locally through our name services.  To do this, we're going to sudo edit the /etc/hosts file.

This file, /etc/hosts, is the first thing checked whenever your local name services is trying to resolve a host name.  If it finds a host-to-IP alias in this file, all further attempts at resolution are halted as it has successfully resolved the host name.  Edit /etc/hosts to resolve your new domain.  It should look something like this:

[cc lang='bash' line_numbers='false']

127.0.0.1    localhost codemonkey codemonkey.shallop.com codeMonkey.shallop.com newW115

[/cc]

The way /etc/hosts works is that you first list an IP address for the domain to resolve to - in this case, we're using 127.0.0.1 which is TCP/IP speak for your local host.  Next we list all of the domain names that are going to resolve to this IP address.  In the example above, we're resolving localhost, codemonkey, codemonkey.shallop.com, codeMonkey.shallop.com, and the new domain: newW115 all to 127.0.0.1.

Whenever I type one of these domains, for example, in to a web browser URL bar, my local host domain services won't go out to my network name servers to resolve the domain name -- it's telling the requesting service that it's 127.0.0.1.  Note, too, that you can alias multiple domain names to the same machine.

Side Note -- this is how you can blacklist certain domains from your browsing experience.  Simple resolve that domain to 127.0.0.1...but that's an article for another day...

You can also have multiple entries resolving to the same IP address.  It would have been just as correct for me to have listed by /etc/hosts file as:

[cc lang='bash' line_numbers='false']

127.0.0.1     localhost 127.0.0.1     codemonkey 127.0.0.1     codeMonkey 127.0.0.1     codemonkey.shallop.com 127.0.0.1     codeMonkey.shallop.com 127.0.0.1     newW115

[/cc]

Finally, also note that a domain extension isn't really required.  We can name our domain pretty much anything we want and as long as you universally use that spelling (and case), then it will resolve locally.

Now that the domain is resolving locally, the next step is to tell Apache2 how to handle the request.  When you type: http://newW115 at the browser, the browser will query local services and receive a response that the domain is handled locally.  Apache2 will then say: "Oh, if it's local, then were do I go to get the files and stuff?"

The configuration for Apache2 is done with virtual hosting.  Technically, you can do this without virtual hosting -- but you can only do it for one domain.  If you want to locally-host multiple domains, you have to use virtual hosting.

The Apache2 configuration file lives in: /etc/httpd/conf and is named: httpd.conf.  This is the main configuration file for Apache2.  Some installations use a sub-directory, usually called something like: vhostsd.conf, and stores the vhosts.conf file within that directory.  That's ok, too.  Apache2 is versatile that way but, for our purposes, we're going to maintain the virtual host configuration(s) within the main conf file.

However, if you wanted to use a separate file for Virtual Hosting, all you need in your httpd.conf file is the directive:

[cc lang='apache' line_numbers='false']

# Virtual hosts Include conf/extra/httpd-vhosts.conf

[/cc]

At the very end of httpd.conf, there's a section called: Name-Based Virtual hosting.  We're going to append this virtual host configuration to the end of this file.

Allow me to side-step for a quick second.  Consider if we were to install phpMyAdmin locally on our server because this is how we want to administer our mySQL database.  We can install the program files anywhere as phpMyAdmin is just another LAMP application, right?  Were we to do that, then we would need a <Directory> directive to Apache2 telling Apache2 where to look for phpMyAdmin.  The domain for phpMyAdmin would still be localhost, or 127.0.0.1 or whatever else you'd defined in /etc/hosts.  The location of the application can live anywhere and we're using the conf file to tell Apache2 how to find and serve it to us when requested.

[cc lang='apache' line_numbers='false']

Alias /phpMyAdmin "/opt/local/www/phpmyadmin" <Directory "/opt/local/www/phpmyadmin"> Options Indexes MultiViews AllowOverride None Order allow,deny Allow from all </Directory>

[/cc]

What this <Directory> directive simply does is tell Apache2 where to look for phpMyAdmin if I enter something like: http://localhost/phpMyAdmin in the URL bar of my browser.  It's not the same thing as giving phpMyAdmin it's own domain at all.

I do this with a lot of my web applications: phpMyAdmin, mcmon, ajaxmytop, nagios, etc., simply because I don't want to remember where the fill path name is of the applications.  It's easier to type: http://localhost/phpMyAdmin that it is to type: http://localhost/webapps/database/phpMyAdmin.

Ok, so back to domains.  Here's the template for the virtual host we've created in /etc/hosts: newW115:

[cc lang='apache' line_numbers='false']

<VirtualHost *:80> ServerName  newW115 ServerAdmin mshallop@gmail.com DocumentRoot /code/webapps/LAMP/newWidget/1-15

DirectoryIndex  index.php

<Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /code/webapps/LAMP/newWidget/1-15> Options Indexes FollowSymLinks MultiViews AllowOverride All Order allow,deny allow from all </Directory>

ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory>

ErrorLog /var/logs/115_error.log

LogFormat       "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat       "%h %l %u %t \"%r\" %>s %b" common LogFormat       "%{Referer}i -> %U" referer LogFormat       "%{User-agent}i" agent        CustomLog       /var/logs/115_log common        ErrorLog        /var/logs/115_error_log

# Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn

CustomLog /var/logs/115_access.log combined ServerSignature On

</VirtualHost>

[/cc]

This is a pretty minimal configuration -- but it's the boilerplate template I use for all new domains and it works.  The lines that in boldface are the lines you should change to match your environment.  Note that you can pretty much put files, such as the log files, where ever you wish.  I changed the names from my normal location but, as a rule, I maintain the entire environment outside of the root filesystem.

Once you've made your changes and saved the file, you'll need to restart Apache2 so that it will read the new configuration.  If there are errors in your configuration file, Apache2 will let you know and will refuse to start.  Make sure you've corrected all errors and, once the server successfully restarts, you should be able to type: http://newW115 into your browser URL bar and have that domain resolve locally, and serve files from the directory you specified in the httpd.conf file.

Over time, as you add additional projects and create new code-domains, you can simply add the new <VirtualHost> directives, appending them, to the httpd.conf file as needed.  When you expire and remove hosts and files, don't forget to remove them from the Apache configuration as well.

And that's pretty much it.  This is a simple thing to set-up as we didn't delve into anything that wasn't plain-vanilla.  For example: SSL configurations, .htacces, or the re-write engine.  That's for another day, another article.

Hope this helps...