VirtualHost Defaulting to Wrong Deployment on Restart

We have a server running seven domains/subdomains. To try to go as minimal as possible here I'll include four of them.

  1. example.com
  2. www.example.com
  3. dwf.example.com
  4. chris.example.com

The server works great 90% of the time, but occasionally we get a larger number of requests and the database server goes down. This then max's out the apache connections, because all the db connections are waiting to timeout. All well and good, we force a restart on the DB, and connections come back up. However, the requests are then coming to the dfw.example.com configuration. That deployment doesn't have our codebase, which is a big issue and I don't understand why that is happening. It also consistently goes to that deployment when this happens and never any of the other 5 we have.

From the documentation I read, I thought Apache read through the httpd.conf file and looked for the first NamedVirtualHost match:

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.

We are running Apache 2.2.15.

Parts I think are relevant from the httpd.conf file:

Listen 80
Listen 255.255.255.255:443

...

ServerName www.example.com

... (this is the exact order, www (https/http), dfw, then all other versions)

NameVirtualHost www.example.com:80
<VirtualHost    www.example.com:80>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/www.example.com
    ServerName www.example.com
    DirectoryIndex index.html
    DirectoryIndex index.php
    LogLevel notice
    ErrorLog /var/log/httpd/www.example.com/error.log
    CustomLog /var/log/httpd/www.example.com/access.log w3c_extended
</VirtualHost>

NameVirtualHost www.example.com:443
<VirtualHost www.example.com:443>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/www.example.com
    ServerName www.example.com
    #certificate stuff
    DirectoryIndex index.html
    DirectoryIndex index.php
    LogLevel notice
    ErrorLog /var/log/httpd/www.example.com/error.log
    CustomLog /var/log/httpd/www.example.com/access.log w3c_extended 
</VirtualHost>

NameVirtualHost dfw.example.com:80
<VirtualHost    dfw.example.com:80>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/dfw.example.com
    ServerName dfw.example.com
    DirectoryIndex index.html
    DirectoryIndex index.php
    LogLevel notice
    ErrorLog /var/log/httpd/dfw.example.com/error.log
    CustomLog /var/log/httpd/dfw.example.com/access.log w3c_extended
</VirtualHost>
NameVirtualHost chris.example.com:443
<VirtualHost    chris.example.com:443>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/chris.example.com
#cert stuff
    ServerName chris.example.com
    DirectoryIndex index.html
    DirectoryIndex index.php
    LogLevel notice
    ErrorLog  /var/log/httpd/chris.example.com/error.log
    CustomLog /var/log/httpd/chris.example.com/access.log w3c_extended
</VirtualHost>

NameVirtualHost chris.example.com:80
<VirtualHost    chris.example.com:80>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/chris.example.com
    ServerName chris.example.com
    DirectoryIndex index.html
    DirectoryIndex index.php
    LogLevel notice
    RewriteLog /home/chris/writinglog.log
    RewriteLogLevel 8
    ErrorLog /var/log/httpd/chris.example.com/error.log
    CustomLog /var/log/httpd/chris.example.com/access.log w3c_extended
    CheckSpelling on
</VirtualHost>

Doing a sudo service httpd restart gets the correct deployment serving again.

Output from apachectl -S:

VirtualHost configuration:
[IPV6ADDRESS]:443 is a NameVirtualHost
         default server chris.example.com (/etc/httpd/conf/httpd.conf:1077)
         port 443 namevhost chris.example.com (/etc/httpd/conf/httpd.conf:1077)
[IPV6ADDRESS]:80 is a NameVirtualHost
         default server chris.example.com (/etc/httpd/conf/httpd.conf:1095)
         port 80 namevhost chris.example.com (/etc/httpd/conf/httpd.conf:1095)
         port 80 namevhost cory.example.com (/etc/httpd/conf/httpd.conf:1128)
IPV4Address:80      is a NameVirtualHost
         default server www.example.com (/etc/httpd/conf/httpd.conf:1035)
         port 80 namevhost dfw.example.com (/etc/httpd/conf/httpd.conf:1065)
        port 80 namevhost www.example.com (/etc/httpd/conf/httpd.conf:1035)
         port 80 namevhost chris.example.com (/etc/httpd/conf/httpd.conf:1095)
IPV4Address:443     is a NameVirtualHost
         default server www.example.com (/etc/httpd/conf/httpd.conf:1047)
         port 443 namevhost www.example.com (/etc/httpd/conf/httpd.conf:1047)
         port 443 namevhost chris.example.com (/etc/httpd/conf/httpd.conf:1077)
wildcard NameVirtualHosts and _default_ servers:
_default_:443          www.example.com (/etc/httpd/conf.d/ssl.conf:74)
Syntax OK

Solution 1:

I am not sure if its good that you have multiple NameVirtualHost * directives. As I understand your question, you yust want a pure NAME Virtual Host and you want that all interfaces on all ports are handled by NameVirtual Host.

I would recoment you to create you hosts like this:

# Use Virtual hosts for all interfaces on all ports
NameVirtualHost *


<VirtualHost *>
  ServerName example.com
  # all other settings for this hostname
</VirtualHost>

<VirtualHost *>
  ServerName www.example.com
  # all other settings for this hostname
</VirtualHost>

<VirtualHost *>
  ServerName dfw.example.com
  # all other settings for this hostname
</VirtualHost>

<VirtualHost *>
  chris.example.com
  # all other settings for this hostname
</VirtualHost>



## ssl.conf
<VirtualHost _default_:443>
  ServerName www.example.com
  # all other settings for this hostname
  SSLEngine on
  #certificate stuff
</VirtualHost>

And if you want to use the same settings for multiple hostnames (e.g. example.com and www.example.com) you could simple add ServerAlias directive where all Hostnames are listed (wildcards like "*.example.com" are possible too).

e.g. a virtual host what matches "example.com" and "www.example.com" could be done like this:

<VirtualHost *>
  ServerName example.com
  ServerAlias example.com www.example.com
  # all other settings for this hostname
</VirtualHost>

p.s. Settings like DirectoryIndex or LogLevel you can define once in your global config. Your virtual host will take the global config and you dont need to add the same value to each host.

Only if one host needs a config different to global values, you must add the special settings in this host.