Why is Apache ignoring VirtualHost directive for first name in hosts file?
- by Peter Taylor
Standard pre-emptive disclaimer: host names, IP addresses, and directories are anonymised.
Problem
We have a server with Apache 2.2 (WAMP) listening on one IP and IIS listening on another. An ASP.Net application running under IIS needs to do some simple GETs from the PHP applications running under Apache to build a unified search results page. This is a virtual server, so the internal IPs are mapped somehow to external ones. The internal DNS system doesn't resolve the publicly published names under which the applications are accessed externally, so the obvious solution was to add them to etc/hosts with the internal IP address:
127.0.0.1 localhost
# 10.0.1.17 is the IP address Apache listens on
10.0.1.17 phpappone.example.com
10.0.1.17 phpapptwo.example.com
After restarting Apache, phpappone.example.com stopped working. Instead of returning pages from that app, Apache was returning pages from the default site. The other PHP apps worked fine.
Relevant configuration
httpd.conf, summarised, says:
ServerAdmin admin@example.com
ServerRoot "c:/server/Apache2"
ServerName www.example.com
Listen 10.0.1.17:80
Listen 10.0.1.17:443
# Not obviously related config options elided
# Nothing obviously astandard
# If you want more details, post a comment
DocumentRoot "c:/server/Apache2/htdocs"
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>
# Fallback for unknown host names
<Directory "c:/server/Apache2/htdocs">
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
# PHP apps common config
<Directory "C:/Inetpub/wwwroot/phpapps">
Options FollowSymLinks -Indexes +ExecCGI
AllowOverride All
Order Allow,Deny
Allow from All
</Directory>
# Virtual hosts
NameVirtualHost 10.0.1.17:80
NameVirtualHost 10.0.1.17:443
<VirtualHost _default_:80>
</VirtualHost>
<VirtualHost _default_:443>
SSLEngine On
SSLCertificateFile "certs/example.crt"
SSLCertificateKeyFile "certs/example.key"
</VirtualHost>
Include conf/vhosts/*.conf
and the vhosts files are e.g.
<VirtualHost 10.0.1.17:80>
ServerName phpappone.example.com
DocumentRoot "c:/Inetpub/wwwroot/phpapps/phpappone"
</VirtualHost>
<VirtualHost 10.0.1.17:443>
ServerName phpappone.example.com
DocumentRoot "c:/Inetpub/wwwroot/phpapps/phpappone"
SSLEngine On
SSLCertificateFile "certs/example.crt"
SSLCertificateKeyFile "certs/example.key"
</VirtualHost>
Buggy behaviour or our misunderstanding?
The documentation for name-based virtual hosts says that
Now when a request arrives, the server will first check if it is using an IP address that matches the NameVirtualHost. If it is, then it will look at each <VirtualHost> section with a matching IP address and try to find one where the ServerName or ServerAlias matches the requested hostname. If it finds one, then it uses the configuration for that server. If no matching virtual host is found, then the first listed virtual host that matches the IP address will be used.
Yet that isn't what we observe. It seems that if the hostname is the first hostname listed against the IP address in etc/hosts then it uses the configuration from the main server and skips the virtual host lookup.
Workarounds
The workaround we've put in place for the time being is to add a fake line to the hosts file:
127.0.0.1 localhost
# 10.0.1.17 is the IP address Apache listens on
10.0.1.17 fakename.example.com
10.0.1.17 phpappone.example.com
10.0.1.17 phpapptwo.example.com
This fixes the problem, but it's not very elegant. In addition, it seems a bit brittle: reordering lines in the hosts file (or deleting the nonsense value) can break it.
The other obvious workaround is to make the main server configuration match that of the troublesome virtual host, but that is equally brittle.
A third option, which is just ugly, would be to change the ASP.Net code to take separate config items for the IP address and the hostname and to implement HTTP manually. Ugh.
The question
Is there a good solution to this problem which localises any "Do not touch this!" explanations to the Apache config files?