Web designers and systems administrators sometimes don't consider
reconfiguring Apache to solve some of their web problems. Sometimes with
the help of a few directives, web designing can be easier and server costs
can be reduced. The VirtualHost
directive is one of these
helpful but often overlooked features. It can be used for running several
domains on a single server with one or many static IP addresses. I can
think of at least two scenarios in which this could be useful. One made
web designing easier for me. The other cut my server costs
significantly.
Consider a web developer who works from home on a Linux machine. He
installed Apache on his computer to make it easier to check his work
before uploading web pages and scripts to the live site. Now here's the
rub: with his browser, he requests a local copy of the main page of Client
A (http://127.0.0.1/client_a/index.html
), which is located in
the /var/www/html/client_a
directory on his computer. On the
index page he has added a link to a CGI script that he just wrote in Perl
(of which he's quite proud) that searches the client's site. The link is
to search.cgi
, which is located in Client A's
cgi-bin
directory (/var/www/cgi-bin/client_a
) on
his computer. You probably see the problem already, but for good form,
I'll finish.
The developer tests the link on his local workstation and all is well.
Feeling pleased, he uploads both index.html
and
search.cgi
to the client's site. When he tries them out
online, though, the new link fails with an error message. The file
/cgi-bin/client_a/search.cgi
does not exist. The file does
exist, of course; it is the directory /cgi-bin/client_a
that
does not exist. The developer has correctly placed
search.cgi
in the client's directory,
/var/www/cgi-bin
(which Apache knows is the alias of calls to
/cgi-bin
). It's just that the client's file tree is
different from the local one.
This scenario won't manifest itself if the web developer only has one
client because all of the files would be in the main directories. Since
he has several clients, he needs separate directories for each, otherwise,
it would be madness to keep track of which files belong to which client.
Also, he would want to name generic, albeit customized files similarly
(for example, index.html
). To deal with linking problems,
most developers use relative paths. However, if a link comes from a file
several subdirectories down, relative paths can be cumbersome (e.g.,
../../../cgi-bin/search.cgi
), especially if he occasionally
relocates or renames files and directories.
Another solution would be to work online with the original files. This is not recommended as he would not be able to test the files before saving them. Another bad idea would be to change the links right before or right after uploading them to conform to the client's server. This is particularly tedious and prone to broken links. The best solution is to reconfigure Apache for virtual hosts (vhosts) so that links will work regardless of whether a file is local or remote.
Consider a systems administrator with a web server either located
physically at her office or rented from a web hosting company (probably a
virtual server with root access). Her boss announces one day that she
wants the admin to setup a web site for a small subsidiary that is to have
its own domain name. The standard impulse would be to set up another
server. The admin would either have to buy a new server and another
static IP address or rent a second virtual server. Neither is necessary.
The VirtualHost
directive can easily solve her problem. Both
sites can be handled by the one server and one static IP address without
much reconfiguring of Apache.
Before digging into Apache directives, let's consider the typical steps
for processing a request to Apache for a document on a virtual host, as
shown in Figure 1. When Apache is started, it scans the configuration
file (/etc/httpd/conf/httpd.conf
) to determine its settings.
It generates a table of the server's IP addresses with a hash (known as a
vhost address set) containing the associated domain names. With
the Apache daemon (httpd
) running and listening at the
appropriate ports (usually just 80), it's ready to receive requests from
clients.
Figure 1 — how Apache processes vhost requests
When a browser goes looking for a document that a user has requested,
it first has a domain name server translate the domain name entered to an
IP address. The browser then sends the user's request to the IP address.
As of HTTP
1.1, the browser must also send to the web server the domain name that
the user entered; it's no longer to be implied. This requirement makes
virtual hosting possible. If Apache has no vhosts, it will use
the main server's DocumentRoot
directory (often set to
/var/www/html
). However, if Apache has been configured for
vhosts, it will compare the client's request to the
ServerName
of each vhost with the same IP address
and port that the request came in on. The accompanying vhost
directives of the first ServerName
that matches the client's
request will be applied.
Within a vhost block--between <VirtualHost>
and </VirtualHost>
tags in
httpd.conf
--many directives may be given, but only two are
typically required: the ServerName
and the
DocumentRoot
directives. The ServerName
directive provides the domain name. The DocumentRoot
directive sets the root directory for the domain. If Apache finds a
vhost with a ServerName
that matches a client
request, it will look in the root directory specified by the
DocumentRoot
directive for files. If it finds what was
requested, it will send copies to the client.
|
Let's look at Apache's vhosts settings. We'll use the second
scenario first since it's simpler. As a matter of good form,
vhost blocks and related directives should go at the end of the
httpd.conf
file. Below is a minimal configuration for the
two virtual hosts:
Listen 80
NameVirtualHost *
<VirtualHost *>
ServerName www.somesite.com
DocumentRoot /var/www/parent
</VirtualHost>
<VirtualHost *>
ServerName www.somesubsidiary.com
DocumentRoot /var/www/subsidiary
</VirtualHost>
First the port is established to which Apache will listen for requests.
Next is a declaration that Apache is to accept virtual host requests on
all (*
) of the server's IP addresses and default ports; in
this case, only port 80. If the server has a few IP addresses, and we
only wanted to allow vhost traffic on one IP address, just the
permitted address could be specified. Likewise, a specific port could be
given to limit traffic further.
NameVirtualHost 10.1.1.50:80
The asterisks inside of the VirtualHost
tags can also be
changed to the same IP address. It could contain a domain name, instead,
but it's not advisable as it adds another layer to start up and can cause
a security hole. Apache can have more than one
NameVirtualHost
directive, and it can have
VirtualHost
directives with IP addresses not tied to a
NameVirtualHost
directive. Virtual hosts that are associated
with a NameVirtualHost
directive by way of the same IP
address (including when both use *
) are considered to be
name-based vhosts; it is the virtual servers' names that
distinguishes them. vhosts that specify IP addresses and don't
have a complementary NameVirtualHost
directives are said to
be IP-based vhosts. Apache can have all name-based
vhosts, all IP-based vhosts, or a mixture. For our
purposes, name-based vhosts are best.
Apache needs to be restarted in order for changes to
httpd.conf
to take effect. To regenerate the vhost
table, service httpd restart
usually works on Linux.
killall -HUP httpd
is a good standby. Regarding the domain
names themselves, although the server, prior to hosting the subsidiary's
site, did not have a vhost block for the parent company's domain,
it must have one now. And to implement a new domain for the subsidiary,
the new domain must be registered and set up in DNS, either on the server
if it's a registered name server, or with the ISP. With a leased virtual
server, the web hosting company needs to add the new domain to their
DNS.
In summary, with vhost settings in Apache, the systems administrator will be able to host both domains on his existing server. It requires very little reconfiguring and she will save a great deal of time and expense by not having to set up a new server.
Returning to the first scenario one, the vhost configuration will need to be changed a bit.
Listen 80
NameVirtualHost 127.0.0.1
<VirtualHost 127.0.0.1>
ServerName localhost
DocumentRoot /var/www
</VirtualHost>
<VirtualHost 127.0.0.1>
ServerName local-client_a.com
DocumentRoot /var/www/client_a
</VirtualHost>
<VirtualHost 127.0.0.1>
ServerName local-client_b.com
DocumentRoot /var/www/client_b
</VirtualHost>
The NameVirtualHost
directive has changed from all IP
addresses of the workstation to only the local, loopback address. This
will make client files accessible only locally . While the second and
third vhost blocks are for client files, the first and default
block is for a menu page (another index.html
) that will be
placed in the /var/www
directory:
<html>
<body>
<h2>Client Sites</h2>
<table width='300' border='0'>
<tr><td width='125'>Client A:</td>
<td><a href='http://local-client_a.com'>Local</a>;</td>
<td><a href='http://www.client_a.com'>On-Line</td></tr>
<tr><td width='125'>Client B:</td>
<td><a href='http://local-client_b.com'>Local</a>;</td>
<td><a href='http://www.client_b.com'>On-Line</td></tr>
</table>
</body>
</html>
This plain web page provides an opening menu when the developer enters
http://localhost/
into his browser. By clicking on a link,
Apache will feed him the local or the remote copy of
index.html
for the client he selects. This requires the
local client domains to be entered into his /etc/hosts
file:
127.0.0.1 localhost
127.0.0.1 local-client_a.com
127.0.0.1 local-client_b.com
All of these entries could go on one line, without repeating the
localhost
address, though it's more manageable with one
client per line.
Let's apply the earlier process analysis to the local vhost
configuration. When the developer enters
http://local-client_a.com/cgi-bin/search.cgi
in his browser
(or clicks on a link from Client A's index page locally to
/cgi-bin/search.cgi
), per /etc/host.conf
, it
will check /etc/hosts
before asking a public DNS server to
translate the domain to an IP address. It will discover that
local-client_a.com
is 127.0.0.1
and will
therefore send the request with an HTTP host header to that local address,
to Apache. Looking in Apache's access log
(/var/log/httpd/access_log
) we can see what was received:
127.0.0.1 - - [01/May/2003:21:16:04 -0500]
"GET /cgi-bin/search.cgi HTTP/1.1" 200 843 "http://local-client_a.com/"
"Mozilla/4.0(compatible;MSIE 5.0;Linux 2.4.20-2.48 i686)Opera 6.11[en]"
Apache then looks up 127.0.0.1
in its vhost address
sets table and finds three vhosts associated with the
address. It then scans for a ServerName
in order of entry
that matches local-client_a.com
. If it fails to find a
match, it will go back to the first entry for 127.0.0.1
(localhost
) and use it. It does, however, find a match with
the second vhost
, so it looks in that vhost's root
directory (/var/www/client_a
) for the subdirectory
cgi-bin
and the file search.cgi
within it. The
result is that links that work on the client's site now work locally.
Just about any main server directive can be added to a vhost block. These are a few in particular that I have found to be handy:
Apache is usually set to record messages in the error_log
and the access_log
files located in
/var/log/httpd
. However, you may want each virtual host to
have its own logs. Add the following to a vhost block to change
its log settings:
ErrorLog /var/log/httpd/client_a-error_log common
CustomLog /var/log/httpd/client_a-access_log common
Of course, you'll have to create the new log files, too. They're plain
text files and can be created with the touch
command:
touch /var/log/httpd/client_a-error_log
Be sure to change the permissions and ownership appropriately. Depending on your configuration, these commands may resemble:
% chmod 644 client*
% chown apache:apache client*
You can insert these next two lines into a vhost block to direct Apache to display customized error messages to the user.
ErrorDocument 404 /messages/404.html
ErrorDocument 500 /messages/500.html
Here Apache is told that the error messages are located in
/messages
. Again, you'll have to create the files as well as
the directory specified. Error 404 is for files not found; error 500 is
for internal server errors — these occur when scripts fail.
On a site that I've administered for over four years now, we used to
have hundreds of flat HTML pages. A year ago we moved all of the content
to a MySQL database and I wrote some Perl scripts that retrieve and
display the data as users request it. Unfortunately, when users come to
the site from a search engine with old data, they sometimes are looking
for an HTML page that no longer exists. A simple fix that I've used for
this is the RedirectMatch
directive.
RedirectMatch permanent .html /cgi-bin/index.cgi
This directive, located inside of the vhost block, redirects
clients who are looking for pages ending in .html
to the main
script. This is much nicer than displaying an error message.
Related Reading ![]() Apache: The Definitive Guide, 3rd Edition |
If you have a vhost that you would like to use for more than
one domain name, then you can put a ServerAlias
directive
inside of the vhost block to link the two domain names
together.
ServerAlias somesite.com secondsite.com
I have some clients that use subdomains. For instance, they have
sales.somesite.com for a somewhat separate web site for their sales
department. There's no special directive for this situation. Just set up
one vhost block for the main domain (ServerName
www.somesite.com
) and another vhost block for the
subdomain (ServerName sales.somesite.com
), with a different
directory for the DocumentRoot
.
Configuring Apache for virtual hosts is pretty simple, but you can run
into problems if you're not sure of the settings or understand the
concepts of the essential directives. For further reading, Apache:
The Definitive Guide (O'Reilly 2003) now has a chapter on virtual
hosts, and there's the Apache site's on-line vhosts documentation.
If you have problems, you can always ask for help on a Usenet forum like
comp.infosystems.www.servers.unix
. However, as with many
things in computers, only add or change the basics, initially. Once you
have virtual hosting working, then start adding other directives. Most
importantly, though, don't be afraid to consider reconfiguring Apache when
faced with a problem with your web site. Just make a backup of the
httpd.conf
file before experimenting.
Russell Dyer is a Perl programmer, MySQL developer, and web designer living and working on a consulting basis in New Orleans.
Return to Apache DevCenter.
Copyright © 2004 O'Reilly Media, Inc.