There is one problem with the Apache HTTP Server that has been annoying me for a very long time, that is the behavior of serving a Default Virtual Host when a requested host is not recognized. The behavior is both non-intuitive and contrary to what people expect to happen.
When Apache, for whatever reason, does not recognize a requested host, it will instead serve up the "default" virtual host in the configuration. As far as I know, it is not possible to disable this behavior, and we are instead advised to keep a "000-default.conf" VHOST file to handle requests for unknown domains.
The default host is picked automatically by Apache, which leads to many configuration related errors.
The host that is picked by Apache is always the first VHOST loaded. Apache loads the VHOST files beginning with numerical order, then alphabetic order. So, if we want to be sure that the host we want as default is actually also picked, then we must name the default configuration file beginning with a zero. Hence, something like "0-default.conf" should work; you can then name the rest of your .conf files as you normally would.
The problem typically occurs when you just installed Apache and started configuring your VHOSTs, or when you have made configuration changes, such as adding or removing a VHOST.
Avoid wildcard (*) in your 000-default.conf
Many examples you find on the internet will either use the domain name, or wildcards (*) in their VirtualHost blocks, but this will not work with a default VHOST.
The problem is that when you have a default configuration, such as a 000-default.conf file that uses the following;
<VirtualHost *:80> # ...
It appears to "override" all other VirtualHost blocks. That is a problem, because we only want it to apply when the name request header does not match any of the VHOSTs that we defined in other VHOST files. This problem has often happened to me on fresh installs of ubuntu+apache.
Note. It is possible to define VHOSTs in the same .conf file, but in Ubuntu we typically keep them in separate files in /etc/apache2/sites-available/.
To enable and disable VHOSTs, we can use the a2ensite [site-name] and a2dissite [site-name] commands — this will create a symbolic link in /etc/apache2/sites-enabled/; we can also do this manually. Regardless, we still need to reload or restart Apache afterwards.
To solve the problem, we should instead specify the local IP address of the server; to determine what the local IP address is, we can use the following command:
ip addr show
ink/ether 0a:12:f5:df:1b:26 brd ff:ff:ff:ff:ff:ff inet 172.31.1.1/20 brd 172.31.15.255 scope global dynamic eth0 valid_lft 3110sec preferred_lft 3110sec inet 172.31.15.25/20 scope global secondary eth0 valid_lft forever preferred_lft forever inet6 fe30::815:f2ff:fedd:1b26/64 scope link valid_lft forever preferred_lft forever
The local IP address is the first inet address. I.e. 172.31.1.1; we can use this in our 000-default.conf file:
<VirtualHost 172.31.1.1:80> # ...
If your server got multiple WAN IP addresses (and thereby multiple network interfaces), and you want the default configuration to apply for all of them, simply include them, separated by space:
<VirtualHost 172.31.15.25:80 172.31.1.1:80> # ...
Wildcards can be unpredictable, so I recommend using IP-based virtual hosting — and by "IP-based" is really just meant that you should configure the VHOSTs to listen on a specific network interface. Unless you got multiple WAN IPs configured, there is probably only one interface.
Picking a default Virtual Host
Apache's way of defining a default VHOST is horrible; I would much prefer a way to explicitly define a default host, or simply have Apache reject the HTTP request while returning a 403 forbidden error, or similar.
I have even had cases where I did actually have a VirtualHost block that matched the requested host, but the request would still be passed on to the "default host", and I would be fumbling in the dark as to why Apache was serving up the wrong website.
In my case, it turned out I had more than one VHOST configuration file that contained the same ServerName value. This apparently causes Apache to instead serve up the default host for both domains.
When you got domains that share the same directory—probably because they are handled by the same code base—then this problem tends to become less apparent. If one domain uses a different DirectoryIndex, then you might notice that the same index file is being used to handle requests for all of the domains.
Note. Unless you got reason to serve a random default host, I suggest you create a 000-default.conf file and explicitly define what is to happen when a unknown domain is requested.
For example, you could create a /var/www/default directory that you link in your 000-default.conf file, which is then served when Apache gets confused.
Safely adding new Virtual Hosts
Another thing you need to be aware of is when adding a new domain (Virtual Host) to your Apache server. It is tempting to simply copy one of the existing files and replace the relevant directives; the problem with doing this, however, is that you often overlook something, and then you might not only end up with a VHOST that is incorrectly configured, you might also break the VHOST that you based your new configuration on.
For example, I have myself, quite a few times, made the above mistake, even thinking I had memorized everything I needed to replace, only to find out I forgot to change the ServerName directive, resulting in all kinds of strange behavior.
Instead, you could create a VHOST template file, and then copy this whenever you need to setup a new domain name.
Then you might ask, who is manually setting up new domain names anyway? Hosting companies will handle this automatically, no doubt? Probably they will. They probably should. I still have not automated it, and I do not think I will do that for my own personal use. I rarely need to add new domains, and when I do, it is usually because I want to create a local domain on my laptop to test my code.