In this post, we will learn how to conﬁgure Apache httpd to provide IPbased and name-based virtual hosts.
Virtual hosts allow a single httpd server to serve content for multiple domains. Based on either the IP address of the server that was connected to, the hostname requested by the client in the http request, or a combination of both, httpd can use different conﬁguration settings, including a different DocumentRoot.
Virtual hosts are typically used when it is not cost-effective to spin up multiple (virtual) machines to serve out many low-trafﬁc sites; for example, in a shared hosting environment.
Configuting Virtual Hosts
Virtual hosts are conﬁgured using <VirtualHost> blocks inside the main conﬁguration. To ease administration, these virtual host blocks are typically not deﬁned inside /etc/httpd/conf/ httpd.conf, but rather in separate .conf ﬁles in /etc/httpd/conf.d/.
The following is an example ﬁle, /etc/httpd/conf.d/site1.conf.
- This block provides access to the DocumentRoot deﬁned further down.
- This is the main tag of the block. The 192.168.0.1:80 part indicates to httpd that this block should be considered for all connections coming in on that IP/port combination.
- Here the DocumentRoot is being set, but only for within this virtual host.
- This setting is used to conﬁgure name-based virtual hosting. If multiple <VirtualHost> blocks are declared for the same IP/port combination, the block that matches ServerName with the hostname: header sent in the client http request will be used. There can be exactly zero or one ServerName directives inside a single <VirtualHost> block. If a single virtual host needs to be used for more than one domain name, one or more ServerAlias statements can be used.
- To help with sorting mail messages regarding the different websites, it is helpful to set unique ServerAdmin addresses for all virtual hosts.
- The location for all error messages related to this virtual host.
- The location for all access messages regarding this virtual host.
If a setting is not made explicitly for a virtual host, the same setting from the main conﬁguration will be used.
Name-based vs. IP-based virtual hosting
By default, every virtual host is an IP-based virtual host, sorting trafﬁc to the virtual hosts based on what IP address the client had connected to. If there are multiple virtual hosts declared for a single IP/port combination, the ServerName and ServerAlias directives will be consulted, effectively enabling name-based virtual hosting.
Wildcards and priority
The IP address part of a <VirtualHost> directive can be replaced with one of two wildcards: _default_ and *. Both have exactly the same meaning: “Match Anything”.
When a request comes in, httpd will ﬁrst try to match against virtual hosts that have an explicit IP address set. If those matches fail, virtual hosts with a wildcard IP address are inspected. If there is still no match, the “main” server conﬁguration is used.
If no exact match has been found for a ServerName or ServerAlias directive, and there are multiple virtual hosts deﬁned for the IP/port combination the request came in on, the ﬁrst virtual host that matches an IP/port is used, with ﬁrst being seen as the order in which virtual hosts are deﬁned in the conﬁguration ﬁle.
When using multiple *.conf ﬁles, they will be included in the alphanumeric sorting order. To create a catch-all (default) virtual host, the conﬁguration ﬁle should be named something like 00default.conf to make sure that it is included before any others.
Troubleshooting Virtual Hosts
When troubleshooting virtual hosts, there are a number of approaches that can help.
- Conﬁgure a separate DocumentRoot for each virtual host, with identifying content.
- Conﬁgure separate logﬁles, both for error logging and access logging, for each virtual host.
- Evaluate the order in which the virtual host deﬁnitions are parsed by httpd. Included ﬁles are read in alphanumeric sort order based on their ﬁlenames.
- Disable virtual hosts one by one to isolate the problem. Virtual host deﬁnitions can be commented out of the conﬁguration ﬁle(s), and include ﬁles can be temporarily renamed to something that does not end in .conf.
- journalctl UNIT=httpd.service can isolate log messages from just the httpd.service service.