Serve Multiple Domains by Using Virtual Hosts
Most people serve more than one domain on their cloud server. Whether you are
serving different domains or different subdomains of the same domain, the procedure is the same. This article describes how to create virtual hosts to serve multiple domains and how to troubleshoot problems with Apache name-based virtual host configurations.
Creating virtual hosts for multiple domains
When a browser sends a request to your server's IP address asking for the contents of your domain name (for example, https://yourexampledomain.com
), your web server serves up an HTTP representation of your site. If the server is serving only one website, it serves the HTML in your /var/www/html
directory, starting with index.html
. But having a unique
server for every website that you want to serve is costly and an inefficient use of your resources.
Name-based virtual hosts enable you to serve content for multiple websites from one server.
One of the first lines in any virtual host configuration file specifies the domain name that
is associated with the virtual host. Following is an example virtual host configuration for Apache, serving domain1.com
:
<VirtualHost \*:80>
ServerName domain1.com
ServerAlias www.domain1.com
</VirtualHost>
The following example shows a virtual host configuration for NGINX:
server {
server_name www.domain1.com;
rewrite ^/(.\*) https://domain1.com/$1 permanent;
Each configuration starts slightly differently, but the same principle applies: that particular virtual host responds to queries for domain1.com
and www.domain1.com
.
To serve different content for different domains, you add another virtual host.
For example, you have a subdomain called blog.domain1.com that is serving a blog.
First you create a folder in your public_html folder with the relevant files for the blog (for example, a WordPress installation).
Then you create a virtual host with the server_name
or ServerName
specified as blog.domain1.com
and configure it to point to the blog files and folders in your public_html
folder.
For more information on virtual hosts, use the Apache document Name-base Virtual Hosts
Troubleshooting
This section shows you how to troubleshoot problems with Apache name-based virtual host configurations. It provides useful commands for testing your virtual host configuration, describes how to interpret their output, and describes how they help fix common virtual host configuration problems.
Restart Apache
Before you can diagnose an issue, ensure that you have restarted Apache since the last time you made changes to your Apache configuration files:
-
For Red Hat distributions use:
sudo /usr/sbin/httpd -k restart
-
For Debian distributions use:
sudo /usr/sbin/apache2 -k restart
If Apache gives you a warning or error message, note it for later. Your next step is to get information about the virtual host configuration.
Get a configuration report
Run the -S
command on the web server to check your virtual host configuration
-
For Red Hat derived distributions use:
sudo /usr/sbin/httpd -S
-
For Debian derived distributions use:
sudo /usr/sbin/apache2 -S
The output shows the virtual host settings from the configuration file. The following example shows the configuration report for a server configured with two name-based virtual hosts: vh1.example.com and vh2.example.com. The numbered lines are explained following the example.
VirtualHost configuration:
wildcard NameVirtualHosts and \_default\_ servers:
[1] \*:80 is a NameVirtualHost
[2] default server vh1.example.com (/etc/httpd/conf/custom/virtualhost.conf:3)
[3] port 80 namevhost vh1.example.com (/etc/httpd/conf/custom/virtualhost.conf:3)
[4] port 80 namevhost vh2.example.com (/etc/httpd/conf/custom/virtualhost.conf:8)
[5] Syntax OK
-
Line [1] reports that the web server is listening on the default port of 80 for all the IP addresses that Apache is listening to, and that name-based virtual hosting is turned on. The * is a wildcard specifying all IP addresses.
-
Line [2] reports the default virtual host that the web server ServerAlias for any requests for which no specific hostname is requested. It also shows the path to the configuration file and line number where this configuration is set.
-
Line [3] reports the port and the name of the first virtual host configuration found, the file it is configured in and the line number its configuration starts on.
-
Line [4] reports the port and the name of the second virtual host configuration found, the file it is configured in and the line number its configuration starts on.
-
Line [5] reports whether the configuration syntax is correct, although that doesn't necessarily mean your site is working
The following output was produced by following virtual host file configuration:
NameVirtualHost \*:80 Turns on name-based host resolution and binds the virtual server to IP addresses and ports as in [1] above. The \* is a wildcard specifying all IP addresses.
<VirtualHost \*:80> Configures the first and default virtual host in [2] & [3] above. It is the default because it is the first virtual host whose IP and port matches those in the NameVirtualHost directive before it.
ServerName vh1.example.com
DocumentRoot /var/www/vhosts/vh1
</VirtualHost>
<VirtualHost \*:80> Configures the second virtual host in [4] above.
ServerName vh2.example.com
DocumentRoot /var/www/vhosts/vh2
</VirtualHost>
Now that that you've seen a basic virtual host configuration looks and how it maps to Apache's own configuration report, you can use those reports to look at common configuration issues. The following sections describe some of these issues and provide guidance for how to fix them.
Hosts not set up as name-based virtual hosts
If running httpd -S
reports the following warning:
[Wed May 18 15:24:51 2011] [warn] \_default\_ VirtualHost overlap on port 80, the first has precedence
VirtualHost configuration:
wildcard NameVirtualHosts and \_default\_ servers:
\*:80 vh1.example.com (/etc/httpd/conf/custom/virtualhost.conf:3)
\*:80 vh2.example.com (/etc/httpd/conf/custom/virtualhost.conf:8)
Syntax OK
This warning indicates that multiple virtual hosts are trying to use the same "socket" without being set up as name-based virtual hosts. This error often occurs when Apache virtual hosts are first created because the default NameVirtualHost
directive is commented out with a hash symbol. That symbol instructs Apache to ignore the directive.
To fix this issue in a default Apache configuration file, verify that the NameVirtualHost *:80
directive is not commented out. If you are working with a minimal Apache configuration file, add a NameVirtualHost *:80
directive above the individual virtual host configurations.
The following example shows the commented directive that caused the error:
#NameVirtualHost \*:80
<VirtualHost \*:80>
ServerName vh1.example.com
DocumentRoot /var/www/vhosts/vh1
</VirtualHost>
<VirtualHost \*:80>
ServerName vh2.example.com
DocumentRoot /var/www/vhosts/vh2
</VirtualHost>
Element missing from VirtualHost directive
If running httpd -S
reports the following error message:
Syntax error on line 8 of /etc/httpd/conf/custom/virtualhost.conf:
<VirtualHost> directive requires additional arguments
This message means that the virtual host's VirtualHost
directive is missing a necessary element. The VirtualHost
directive is the first line of any individual virtual host configuration. In this case, the error is on the line 8 of the configuration file /etc/httpd/conf/custom/virtualhost.conf
.
Following is the Apache configuration that produced this above error:
NameVirtualHost \*:80
<VirtualHost \*:80>
ServerName vh1.example.com
DocumentRoot /var/www/vhosts/vh1
</VirtualHost>
<VirtualHost>
ServerName vh2.example.com
DocumentRoot /var/www/vhosts/vh2
</VirtualHost>
Note that the second VirtualHost
directive has no IP address or port specified, which is the cause of the error.
Following is a corrected version of the preceding example, with the addition of \*:80
to the virtual host's directive. As always, the \*
is a wildcard specifying all IP addresses.
NameVirtualHost \*:80
<VirtualHost \*:80>
ServerName vh1.example.com
DocumentRoot /var/www/vhosts/vh1
</VirtualHost>
<VirtualHost \*:80>
ServerName vh2.example.com
DocumentRoot /var/www/vhosts/vh2
</VirtualHost>
Port numbers don't match
If running httpd -S
, shows that a virtual host is listed above the is a NameVirtualHost
line:
VirtualHost configuration:
wildcard NameVirtualHosts and \_default\_ servers:
\*:800 vh2.example.com (/etc/httpd/conf/custom/virtualhost.conf:8)
\*:80 is a NameVirtualHost
default server vh1.example.com (/etc/httpd/conf/custom/virtualhost.conf:3)
port 80 namevhost vh1.example.com (/etc/httpd/conf/custom/virtualhost.conf:3)
Syntax OK
In this example, the configuration test reports the vh2.example.com
configuration before it reports the NameVirtualHost
configuration. You might see this error if the VirtualHost IP address or port doesn’t match the IP address or port of the web server’s NameVirtualHost
directive. In this example, the report shows that vh2.example.com
uses port 800 rather than port 80. The port number was mistyped when the vh2.example.com
virtual host's listening port was configured. As a result, Apache treats vh2.example.com
as a separate port-based virtual host.
The httpd -S
test command doesn’t warn you about this issue because it’s permissible to configure virtual hosts to use any port, such as 800, without them being part of the name-based virtual host configuration on the same server.
If you do experience this error, you will probably see content from the default virtual host (vh1.example.com
in this example) when you try to view the site in your web browser.
To help you map the preceding output to its configuration file, following is the virtual host configuration that created this error:
NameVirtualHost \*:80
<VirtualHost \*:80>
ServerName vh1.example.com
DocumentRoot /var/www/vhosts/vh1
</VirtualHost>
<VirtualHost \*:800>
ServerName vh2.example.com
DocumentRoot /var/www/vhosts/vh2
</VirtualHost>
Document root directory does not exist
If running httpd -S
reports the following error:
Warning: DocumentRoot [/etc/httpd/var/www/vhosts/vh2] does not exist
This error indicates that the directory specified as containing the website files for the vh2.example.com
virtual host does not exist, or that Apache cannot access it. Similar errors can appear for any of the file paths specified in a virtual host configuration, such as the paths to the virtual host's log files.
To fix this error, ensure that you created the directory. If you did create it, verify that there are no mistakes in the DocumentRoot
directive. A common mistake is to omit the path's initial slash (/). Leaving out the slash instructs Apache to read the path—the DocumentRoot
path in this case—as a relative path, that is, as a path relative to the main Apache configuration's ServerRoot
path.
The following example shows just one of the ways in which this error is created. The path for the DocumentRoot
directive in the first virtual host starts with a slash but the second one doesn’t.
ServerRoot /etc/httpd
NameVirtualHost \*:80
<VirtualHost \*:80>
ServerName vh1.example.com
DocumentRoot /var/www/vhosts/vh1
</VirtualHost>
<VirtualHost \*:80>
ServerName vh2.example.com
DocumentRoot var/www/vhosts/vh2
</VirtualHost>
Using cURL to test your site
After you check the virtual host configuration files and the httpd -S
command reports no issues, try to access your site by using cURL:
curl -I www.example.com
The output should look something like this:
HTTP/1.1 200 OK
Date: Sat, 07 May 2011 15:09:50 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Mon, 25 Apr 2011 11:07:43 GMT
ETag: "2c32e-77-4a1bc37723dc0"
Accept-Ranges: bytes
Content-Length: 119
Content-Type: text/html; charset=UTF-8
The first line shows the status code. You want to see 200 OK
, as shown in the example. If that's what you see, test the web server with your browser, but consider that your browser might display a cached page.
If you don't see 200 OK
, you might see one of the following common messages:
-
curl: (6) Couldn't resolve host vh1.example.com
If cURL reports that it can’t find the host, verify that there is an A record for the
domain that points to the correct IP address for your server. You can use the dig to do this:dig vh1.example.com
-
curl: (7) couldn't connect to host
Verify that your Apache configuration files include the necessary
Listen
directives and that they are not commented out. It needsListen 80
at the very least.Another way to verify this is to check the error log. The default error log is at
/var/log/httpd/error_log
on Red Hat systems and/var/log/apache2/error_log
on Debian systems. If no port is specified for Apache to listen on, the message no listening sockets available, shutting down follows Apache's attempt to restart.[notice] SIGHUP received. Attempting to restart no listening sockets available, shutting down Unable to open logs
-
HTTP/1.1 403 Forbidden
This response indicates that the permissions that allow Apache access to the page that you're requesting are not correct. Perhaps the directory permissions are incorrect, or it could be the page itself.
You might also see a 403 response in the following situations:
- The `DocumentRoot` contains no index file—-typically named `index.html` or `index.php`. Note that the file name is case sensitive.
- The virtual host doesn't contain a `DirectoryIndex` directive specifying the default index file.
The Apache error logs usually show which directory or file has the permissions set incorrectly. Individual virtual hosts might write errors to their own logs if they were configured to, so check these logs too.
Don’t be discouraged by the amount of data in a busy server's log files. Instead, use the tail command to selectively view just the most recent ten lines of a log. For example:
tail /var/log/apache2/error\_log
You can see new entries as they are added to the error log, or any log, while you test the server if you instruct the tail
command to "follow" the log. For example:
tail -f /var/log/httpd/error\_log
Common permissions-related errors
Following are examples of some common permissions-related configuration errors that can appear in Apache's logs:
-
The following log entry shows that permissions on the
index.html
file forvh2.example.com
are denying access to Apache.[error] [client 203.0.113.96] (13)Permission denied: access to /index.html denied
-
The following log entry shows that permissions on the
/var/www/vhosts/vh2
directory are blocking Apache's read request.[error] [client 203.0.113.96] (13)Permission denied: file permissions deny server access: /var/www/vhosts/vh2/index.html
-
The following log entry shows that Apache does not have execute or read
permissions on one of the directories aboveDocumentRoot
.[error] [client 203.0.113.96] (13)Permission denied: access to / denied
Updated 12 months ago