Chapter 4. Virtual Hosts

A web server system supports multiple web sites in a way similar to a person who responds to her given name, as well as her nickname. In the Apache configuration file, each alternate identity, and probably the “main” one as well, is known as a virtual host (sometimes written as vhost) identified with a <VirtualHost> container directive. Depending on the name used to access the web server, Apache responds appropriately, just as someone might answer differently depending on whether she is addressed as “Miss Jones” or “Hey, Debbie!” If you want to have a single system support multiple web sites, you must configure Apache appropriately.

There are two different types of virtual host supported by Apache. The first type, called address-based or IP-based, is tied to the numeric network address used to reach the system. Bruce Wayne never answered the parlour telephone with “Batman here!” nor did he answer the phone in the Batcave by saying, “Bruce Wayne speaking.” However, it’s the same person answering the phone, just as it’s the same web server receiving the request.

The other type of virtual host is name-based, because the server’s response depends on what it is called. To continue the telephone analogy, consider an apartment shared by multiple roommates; you call the same number whether you want to speak to Dave, Joyce, Amaterasu, or George. Just as multiple people may share a single telephone number, multiple web sites can share the same IP address. However, all IP addresses shared by multiple Apache virtual hosts need to be declared with a NameVirtualHost directive.

In the most simple of Apache configurations, there are no virtual hosts. Instead, all of the directives in the configuration file apply universally to the operation of the server. The environment defined by the directives outside any <VirtualHost> containers is sometimes called the default server or perhaps the global server. There is no official name for it, but it can become a factor when adding virtual hosts to your configuration.

But what happens if you add a <VirtualHost> container to such a configuration? How are those directives outside the container interpreted, and what is their effect on the virtual host?

The answer is not a simple one: essentially, the effect is specific to each configuration directive. Some get inherited by the virtual hosts, some get reset to a default value, and some pretend they’ve never been used before. You’ll need to consult the documentation for each directive to know for sure.

There are two primary forms of virtual hosts: IP-based virtual hosts, where each virtual host has its own unique IP address; and name-based virtual hosts, where more than one virtual host runs on the same IP address but with different names. This chapter will show you how to configure each one and how to combine the two on the same server. You’ll also learn how to fix common problems that occur with virtual hosts.

4.1. Setting Up Name-Based Virtual Hosts

Problem

You have only one IP address, but you want to support more than one web site on your system.

Solution

Use the NameVirtualHost * directive in conjunction with <VirtualHost> sections:

ServerName 127.0.0.1
NameVirtualHost *

<VirtualHost *>
    ServerName TheSmiths.name
    DocumentRoot "C:/Apache/Sites/TheSmiths"
</VirtualHost>
        
<VirtualHost *>
    ServerName JohnSmith.name
    DocumentRoot "C:/Apache/Sites/JustJohnSmith"
</VirtualHost>

Discussion

With IP addresses increasingly hard to come by, name-based virtual hosting is the most common way to run multiple web sites on the same Apache server. The previous recipe works, for most users, in most virtual hosting situations.

The * in the previous rules means that the specified hosts run on all addresses. For a machine with only a single address, this means that it runs on that address but will also run on the loopback , or localhost address. Thus if you are sitting at the physical server system, you can view the web site.

The argument to the <VirtualHost> container directive is the same as the argument to the NameVirtualHost directive. Putting the hostname here may ignore the virtual host on server startup, and requests to this virtual host may unexpectedly go somewhere else. If your name server is down or otherwise unresponsive at the time that your Apache server is starting up, then Apache can’t match the particular <VirtualHost> section to the NameVirtualHost directive to which it belongs.

Requests for which there is not a virtual host listed will go to the first virtual host listed in the configuration file. In the case of the previous example, hostnames that are not explicitly mentioned in one of the virtual hosts will be served by the TheSmiths.name virtual host.

It is particularly instructive to run httpd -S and observe the virtual host configuration as Apache understands it, to see if it matches the way that you understand it. httpd -S returns the virtual host configuration, showing which hosts are name-based, which are IP-based, and what the defaults are.

Multiple names can be listed for a particular virtual host using the ServerAlias directive, as shown here:

ServerName TheSmiths.name
ServerAlias www.TheSmiths.name Smith.Family.name

It is important to understand that virtual hosts render the server listed in the main body of your configuration file no longer accessible—you must create a virtual host section explicitly for that host. List this host first, if you want it to be the default server.

Adding name-based virtual hosts to your Apache configuration does not magically add entries to your DNS server. You must still add records to your DNS server so that the names resolve to the IP address of the server system. When users type your server name(s) into their browser location bars, their computers first contact a DNS server to look up that name and resolve it to an IP address. If there is no DNS record, then their browsers can’t find your server.

For more information on configuring your DNS server, consult the documentation for the DNS software you happen to be running, or talk to your ISP if you’re not running your own DNS server.

4.2. Designating One Name-Based Virtual Host as the Default

Problem

You want all requests, whether they match a virtual host or use an IP address, to be directed to a default host, possibly with a “host not found” error message.

Solution

Add the following <VirtualHost> section, and list it before all of your other ones:

<VirtualHost *>
    ServerName default
    DocumentRoot /www/htdocs
    ErrorDocument 404 /site_list.html
</VirtualHost>

Discussion

Note that this recipe is used in the context of name-based virtual hosts, so it is assumed that you have other virtual hosts that are also using the <VirtualHost *> notation, and that there is also an accompanying NameVirtualHost * appearing above them. We have used the default name for clarity; you can call it whatever you want.

Setting the ErrorDocument 404 to a list of the available sites on the server directs the user to useful content, rather than leaving him stranded with an unhelpful 404 error message. You may wish to set DirectoryIndex to the site list as well, so that users who go directly to the front page of this site also get useful information.

It’s a good idea to list explicitly all valid hostnames either as ServerNames or ServerAliases, so that nobody ever winds up at the default site. However, if someone accesses the site directly by IP address, or if a hostname is added to the address in question before the appropriate virtual host is created, the user still gets useful content.

See Also

4.3. Setting Up Address-Based Virtual Hosts

Problem

You have multiple IP addresses assigned to your system, and you want to support one web site on each.

Solution

Create a virtual host section for each IP address you want to list on:

ServerName 127.0.0.1

<VirtualHost 10.0.0.1>
    ServerName TheSmiths.name
    DocumentRoot "C:/Apache/Sites/TheSmiths"
</VirtualHost>

<VirtualHost 10.0.0.2>
    ServerName JohnSmith.name
    DocumentRoot "C:/Apache/Sites/JustJohnSmith"
</VirtualHost>

Discussion

The virtual hosts defined in this example catch all requests to the specified IP addresses, regardless of what hostname is used to get there. Requests to any other IP address not listed go to the virtual host listed in the main body of the configuration file.

The ServerName specified is used as the primary name of the virtual host, when needed, but is not used in the process of mapping a request to the correct host. Only the IP address is consulted to figure out which virtual host to serve requests from, not the Host header field.

4.4. Creating a Default Address-Based Virtual Host

Problem

You want to create a virtual host to catch all requests that don’t map to one of your address-based virtual hosts.

Solution

Use the _default_ keyword to designate a default host:

<VirtualHost _default_>
    DocumentRoot /www/htdocs
</VirtualHost>

Discussion

The _default_ keyword creates a virtual host that catches all requests for any address:port combinations for which there is not a virtual host configured.

The _default_ directive may be used in conjunction with a particular port number, such as:

<VirtualHost _default_:443>

Using this syntax means that the specified virtual host catches all requests to port 443, on all addresses for which there is not an explicit virtual host configured. This is the usual way to set up SSL, which you see in the default SSL configuration file.

_default_ typically does not work as people expect in the case of name-based virtual hosts. It does not match names for which there are no virtual host sections, only address:port combinations for which there are no virtual hosts configured. If you wish to create a default name-based host, see Recipe 4.2.

See Also

4.5. Mixing Address-Based and Name-Based Virtual Hosts

Problem

You have multiple IP addresses assigned to your system, and you want to support more than one web site on each address.

Solution

Provide a NameVirtualHost directive for each IP address, and proceed as you did with a single IP address:

ServerName 127.0.0.1
NameVirtualHost 10.0.0.1
NameVirtualHost 10.0.0.2

<VirtualHost 10.0.0.1>
    ServerName TheSmiths.name
    DocumentRoot "C:/Apache/Sites/TheSmiths"
</VirtualHost>

<VirtualHost 10.0.0.1>
    ServerName JohnSmith.name
    DocumentRoot "C:/Apache/Sites/JustJohnSmith"
</VirtualHost>

<VirtualHost 10.0.0.2>
    ServerName TheFergusons.name
    DocumentRoot "C:/Apache/Sites/TheFergusons"
</VirtualHost>

<VirtualHost 10.0.0.2>
    ServerName DoriFergusons.name
    DocumentRoot "C:/Apache/Sites/JustDoriFerguson"
</VirtualHost>

Discussion

Using the address of the server, rather than the wildcard * argument, makes the virtual hosts listen only to that IP address. However, you should notice that the argument to <VirtualHost> still must match the argument to the NameVirtualHost with which they are connected.

4.6. Mass Virtual Hosting with mod_vhost_alias

Problem

You want to host many virtual hosts, all of which have exactly the same configuration.

Solution

Use VirtualDocumentRoot and VirtualScriptAlias provided by mod_vhost_alias .

VirtualDocumentRoot /www/vhosts/%-1/%-2.1/%-2/htdocs
VirtualScriptAlias  /www/vhosts/%-1/%-2.1/%-2/cgi-bin

Discussion

This recipe uses directives from mod_vhost_alias , which you may not have installed when you built Apache, as it is not one of the modules that is enabled by default.

These directives map requests to a directory built up from pieces of the hostname that was requested. Each of the variables represents one part of the hostname, so that each hostname is be mapped to a different directory.

In this particular example, requests for content from www.example.com is served from the directory /www/vhosts/com/e/example/htdocs, or from /www/vhosts/com/e/example/cgi-bin (for CGI requests). The full range of available variables is shown in Table 4-1.

Table 4-1. mod_vhost_alias variables

Variable

Meaning

%%

insert a %

%p

insert the port number of the virtual host

%M.N

insert (part of) the name

M and N may have positive or negative integer values, which have the following meanings (see Table 4-2).

Table 4-2. Meanings of variable values

Value

Meaning

0

The whole name

1

The first part of the name

-1

The last part of the name

2

The second part of the name

-2

The next-to-last part of the name

2+

The second, and all following, parts

-2+

The next-to-last, and all proceeding, parts

When the value is placed in the first part of the argument—in the M part of %M.N—it refers to parts of the hostname itself. When used in the second part—the N—refers to a particular letter from that part of the hostname. For example, in hostname www.example.com, the meanings of the variables are as shown in Table 4-3.

Table 4-3. Example values for the hostname www.example.com

Value

Meaning

%0

www.example.com

%1

www

%2

example

%3

com

%-1

com

%-2

example

%-3

www

%-2.1

e

%-2.2

x

%-2.3+

ample

Depending on the number of virtual hosts, you may wish to create a directory structure subdivided alphabetically by domain name, by top-level domain, or simply by hostname.

4.7. Mass Virtual Hosting Using Rewrite Rules

Problem

Although there is a module—mod_vhost_alias—which is explicitly for the purpose of supporting large numbers of virtual hosts, it is very limiting and requires that every virtual host be configured exactly the same way. You want to support a large number of vhosts, configured dynamically, but, at the same time, you want to avoid mod_vhost_alias.

Solution

Use directives from mod_rewrite to map to a directory based on the hostname:

RewriteEngine on
RewriteCond   %{HTTP_HOST}     ^(www\.)?([^.]+)\.com$
RewriteRule   ^(.*)$   /home/%2$1

Discussion

mod_vhost_alias is useful, but it is best for settings where each virtual host is identical in every way but hostname. Using mod_vhost_alias precludes the use of other URL-mapping modules, such as mod_userdir, mod_rewrite, and mod_alias, and it can be very restrictive. Using mod_rewrite is less efficient, but it is more flexible.

For example, when using mod_vhost_alias, you must do all of your hosts with mod_vhost_alias; whereas with this alternate approach, you can do some of your hosts using the rewrite rules and others using conventional virtual host configuration techniques.

The directives in the Solution map requests for www.something.com (or without the www) to the directory /home/something.

4.8. SSL and Name-Based Virtual Hosts

Problem

You want to have multiple SSL web sites on the same server.

Solution

In most common implementations of SSL, you are limited to one SSL host per address and port number. Thus, either you need to have a unique IP address for each SSL host or run them on alternate ports to get more than one on a particular IP address:

Listen 443
Listen 444

<VirtualHost 10.0.1.2:443>
    ServerName secure1.example.com
    DocumentRoot /www/vhosts/secure1

    SSLEngine On
    SSLCertificateFile    /www/conf/ssl/secure1.crt
    SSLCertificateKeyFile /www/conf/ssl/secure1.key
</VirtualHost>

<VirtualHost 10.0.1.3:443>
    ServerName secure2.example.com
    DocumentRoot /www/vhosts/secure2

    SSLEngineOn
    SSLCertificateFile    /www/conf/ssl/secure2.crt
    SSLCertificateKeyFile /www/conf/ssl/secure2.key
</VirtualHost>

<VirtualHost 10.0.1.3:444>
    ServerName secure3.example.com
    DocumentRoot /www/vhosts/secure3

    SSLEngineOn
    SSLCertificateFile    /www/conf/ssl/secure3.crt
    SSLCertificateKeyFile /www/conf/ssl/secure3.key
</VirtualHost>

Discussion

The limitation that restricts you to one SSL host per IP address is not a limitation imposed by Apache but by the way that SSL works. When the browser connects to the server, the first thing that it does is negotiate for a secure connection. During this process, the server sends its certificate to the client, which indicates that the rest of the transaction will be encrypted.

Because this happens before the browser tells the server what resource it wants, this part of the conversation can be based only on the IP address on which the client connected. By the time the server receives the Host header field, it is too late—the certificate has already been sent.

It is possible to run SSL hosts on ports other than port 443, if the port number is explicitly specified in the URL. This would allow you to get around this limitation, but it would put an additional burden on the end user to type the correct URL with the port number.

See Also

4.9. Logging for Each Virtual Host

Problem

You want each virtual host to have its own logfiles.

Solution

Specify Errorlog and CustomLog within each virtual host declaration:

<VirtualHost *>
    ServerName   waldo.example.com
    DocumentRoot /home/waldo/www/htdocs

    ErrorLog     /home/waldo/www/logs/error_log
    CustomLog    /home/waldo/www/logs/access_log combined
</VirtualHost>

Discussion

The various logging directives can be placed either in the main body of your configuration file or within a <VirtualHost> section. When it is placed within a virtual host, log entries for that virtual host go in the specified logfile, rather than into the log file(s) defined in the main server configuration.

Warning

Each logfile counts against the total number of files and network connections your server is allowed to have. If you have 100 virtual hosts, each with its own error and activity log, that’s 200 open channels—and if the server’s quota is 256, you can only handle 56 concurrent requests at any one time.

In the recipe given here, the logfiles are placed within the home directory of a particular user, rather than in the main log directory. This gives you easier access to those files, but you still need to take adequate precautions to set the permissions on the directory in question. Consult Chapter 6 for a discussion on file permissions.

4.10. Splitting Up a LogFile

Problem

Due to a large number of virtual hosts, you want to have a single logfile and split it up afterwards.

Solution

LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost
CustomLog logs/vhost_log vhost

Then, after rotating your logfile:

split-logfile < logs/vhost_log

Discussion

The LogFormat directive in this recipe creates a logfile that is similar to the common log file format but additionally contains the name of the virtual host being accessed. The split-logfile utility splits up this logfile into its constituent virtual hosts.

See Also

4.11. Port-Based Virtual Hosts

Problem

You want to present different content for HTTP connections on different ports.

Solution

Explicitly list the port number in the <VirtualHost> declaration:

    Listen 8080

    <VirtualHost 10.0.1.2:8080>
        DocumentRoot /www/vhosts/port8080
    </VirtualHost>

    Listen 9090

    <VirtualHost 10.0.1.2:9090>
        DocumentRoot /www/vhosts/port9090
    <VirtualHost>

Discussion

Port-based virtual hosting is somewhat less common than other techniques shown in this chapter. However, there are a variety of situations in which it can be useful. If you have only one IP address, have no ability to add hostnames to DNS, or if your ISP blocks in-bound traffic on port 80, it may be useful to run virtual hosts on other ports.

Visitors to your web site must list the port number in the URL that they use. For example, to load content from the second virtual host previously listed, the following URL might be used:

http://server.example.com:9090/

4.12. Displaying the Same Content on Several Addresses

Problem

You want to have the same content displayed on two of your addresses.

Solution

Specify both addresses in the <VirtualHost> directive:

NameVirtualHost 192.168.1.1
NameVirtualHost 172.20.30.40

<VirtualHost 192.168.1.1 172.20.30.40>
    DocumentRoot /www/vhosts/server
    ServerName server.example.com
    ServerAlias server
</VirtualHost>

Discussion

This setup is most useful on a machine that has addresses that are internal to your network, as well as those that are accessible only from outside your network. If these are the only addresses, you could use the * notation introduced in Recipe 4.1. However, if there are more addresses, this allows you to specify what content appears on what address.

Get Apache Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.