When setting up name-based virtual hosting with wildcard ServerName directives in Apache, many administrators encounter unexpected behavior where requests always default to the first defined VirtualHost. This occurs particularly when using multiple custom TLDs (like *.test and *.dev) with VirtualDocumentRoot.
Contrary to common assumption, Apache doesn't perform pattern matching when selecting among multiple wildcard ServerName entries. The selection follows this order:
- Exact ServerName match
- Exact ServerAlias match
- First defined VirtualHost if no exact matches
In your configuration:
NameVirtualHost 10.10.0.205
<VirtualHost 10.10.0.205>
ServerName *.test
VirtualDocumentRoot /var/www/%-3.0.%-2/test/%1/
</VirtualHost>
<VirtualHost 10.10.0.205>
ServerName *.dev
VirtualDocumentRoot /var/www/%-3.0.%-2/dev/%1/
</VirtualHost>
Apache treats *.test and *.dev as literal strings, not as patterns to match against. This explains why requests to www.domain.com.dev always hit the first VirtualHost.
Option 1: Use Separate IP Addresses
The most straightforward solution is to assign different IPs to each TLD:
NameVirtualHost 10.10.0.205
NameVirtualHost 10.10.0.206
<VirtualHost 10.10.0.205>
ServerName test
VirtualDocumentRoot /var/www/%-3.0.%-2/test/%1/
</VirtualHost>
<VirtualHost 10.10.0.206>
ServerName dev
VirtualDocumentRoot /var/www/%-3.0.%-2/dev/%1/
</VirtualHost>
Option 2: Use mod_rewrite for TLD Routing
More flexible solution using rewrite rules:
NameVirtualHost 10.10.0.205
<VirtualHost 10.10.0.205>
ServerName vhost-router
RewriteEngine On
# Capture the TLD part
RewriteCond %{HTTP_HOST} \.([a-z]+)$
RewriteCond %1 ^(test|dev)$
# Route to appropriate directory structure
RewriteRule ^(.*)$ /var/www/%-3.0.%-2/%1/%1/ [L]
VirtualDocumentRoot /var/www/%-3.0.%-2/%1/%1/
</VirtualHost>
Option 3: Use mod_vhost_alias with ServerAlias
Alternative approach with explicit ServerAlias entries:
NameVirtualHost 10.10.0.205
<VirtualHost 10.10.0.205>
ServerName test
ServerAlias *.test
VirtualDocumentRoot /var/www/%-3.0.%-2/test/%1/
</VirtualHost>
<VirtualHost 10.10.0.205>
ServerName dev
ServerAlias *.dev
VirtualDocumentRoot /var/www/%-3.0.%-2/dev/%1/
</VirtualHost>
For production environments, consider these approaches:
- Use dedicated IP addresses when possible
- Combine with mod_macro for maintainability
- Implement proper DNS wildcard records
- Use consistent directory naming conventions
Always verify your setup with:
apachectl -S
curl -v http://test.example.dev
tail -f /var/log/apache2/access.log
Remember that DNS resolution must be properly configured for your custom TLDs to work correctly.
When dealing with name-based virtual hosts in Apache, many developers assume that wildcard ServerName directives (*.test, *.dev) will follow intuitive pattern matching rules. However, the actual behavior is more nuanced:
# Problematic configuration example:
NameVirtualHost 10.10.0.205
ServerName *.test
VirtualDocumentRoot /var/www/%-3.0.%-2/test/%1/
ServerName *.dev
VirtualDocumentRoot /var/www/%-3.0.%-2/dev/%1/
Apache's vhost selection algorithm doesn't perform wildcard pattern matching the way you might expect. Instead:
- It first looks for an exact ServerName match
- Then checks ServerAlias for exact matches
- If no match found, uses the first defined VirtualHost for that IP:port combination
Here are three proven approaches to achieve your goal:
Option 1: Use Separate IP Addresses
NameVirtualHost 10.10.0.205
NameVirtualHost 10.10.0.206
ServerName whatever.test
VirtualDocumentRoot /var/www/%-3.0.%-2/test/%1/
ServerName whatever.dev
VirtualDocumentRoot /var/www/%-3.0.%-2/dev/%1/
Option 2: Use mod_rewrite in Fallback VHost
ServerName fallback.example.com
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(.*)\.dev$
RewriteRule ^(.*)$ http://%1.dev$1 [L]
# Similar rule for .test domains
Option 3: Use mod_vhost_alias with ServerPath
ServerName catch-all
ServerPath "/dev/"
VirtualDocumentRoot /var/www/%-3.0.%-2/dev/%1/
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/dev/
RewriteRule ^(.*)$ /dev/$1
- Always place your most specific VirtualHost definitions first
- Use
ServerAlias
for additional domain patterns - Consider using
mod_macro
to reduce configuration duplication - Test with
apachectl -S
to verify your vhost matching order
Add these directives to your vhosts for better debugging:
LogLevel debug
CustomLog /var/log/apache2/vhost-access.log "%v %h %l %u %t \"%r\" %>s %b"