When configuring Apache to handle multiple domain aliases pointing to the same content, we encounter an interesting behavior where all requests are internally served using the ServerName value. This becomes problematic when you need to:
- Properly detect the original requested hostname
- Implement conditional redirects based on the request URL
- Maintain SEO-friendly redirects
Here's the typical configuration that doesn't work for our purposes:
<VirtualHost *:80>
ServerName www.example.com
ServerAlias foo.example.com bar.example.com example.com
DocumentRoot /var/www/html
# This won't work as expected
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com$1 [L,R=301]
</VirtualHost>
The key is to capture the original host header before Apache normalizes it:
<VirtualHost *:80>
ServerName www.example.com
ServerAlias foo.example.com bar.example.com example.com
DocumentRoot /var/www/html
RewriteEngine On
# Capture original host before Apache processes it
RewriteCond %{HTTP:X-Forwarded-Host} !^www\.example\.com$ [NC,OR]
RewriteCond %{HTTP:X-Forwarded-Host} ^$
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com$1 [L,R=301]
</VirtualHost>
For more complex scenarios, consider this pattern:
# Catch-all for non-www domains
<VirtualHost *:80>
ServerName example.com
ServerAlias foo.example.com bar.example.com
RewriteEngine On
RewriteRule ^(.*)$ http://www.example.com$1 [L,R=301]
</VirtualHost>
# Primary domain configuration
<VirtualHost *:80>
ServerName www.example.com
DocumentRoot /var/www/html
# Your main configuration here
</VirtualHost>
- Always use 301 (permanent) redirects for SEO purposes
- Test with
curl -I
to verify response headers - Consider SSL/TLS configurations if using HTTPS
- Monitor your .htaccess for conflicts if used
<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com *.example.com
# Log formats
LogFormat "%{Host}i %h %l %u %t \"%r\" %>s %b" vhost_combined
CustomLog ${APACHE_LOG_DIR}/access.log vhost_combined
RewriteEngine On
# Handle naked domain
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com$1 [L,R=301]
# Handle subdomains
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteCond %{HTTP_HOST} ^([a-z0-9-]+)\.example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com$1 [L,R=301]
</VirtualHost>
When implementing domain consolidation in Apache2, many developers encounter a fundamental behavior: VirtualHosts always serve content using the primary ServerName
, even when accessed via ServerAlias
entries. This makes it impossible to perform conditional redirects based on the requested hostname without additional configuration.
Apache's documented behavior states that requests matching any ServerAlias
pattern will be processed by the VirtualHost but will inherit the ServerName
in server variables. This explains why mod_rewrite always sees the primary domain:
# Typical problematic configuration
ServerName www.example.com
ServerAlias example.com *.example.com foo.example.com
DocumentRoot /var/www/html
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com$1 [R=301,L]
The most reliable approach involves creating a dedicated VirtualHost that captures all non-canonical domains before they reach your primary host:
# Catch-all redirect VirtualHost (must appear FIRST in config)
ServerName example.com
ServerAlias *.example.com
RewriteEngine On
RewriteRule ^(.*)$ http://www.example.com$1 [R=301,L]
# Primary VirtualHost (must appear SECOND)
ServerName www.example.com
DocumentRoot /var/www/html
# Normal configuration here
For simpler cases where you control all domains, you can use this more concise approach:
ServerName www.example.com
ServerAlias example.com *.example.com
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com$1 [R=301,L]
DocumentRoot /var/www/html
- Order Matters: VirtualHosts are processed in configuration file order
- SSL Certificates: For HTTPS, ensure your certificate covers all aliases
- Performance: Redirects add extra HTTP requests - minimize their use
Always verify your setup with curl:
curl -I http://example.com
curl -I http://foo.example.com
curl -I http://www.example.com
Look for 301 Moved Permanently
responses from non-canonical domains and direct serving from your primary domain.
For complete solutions, duplicate your redirect logic in both protocol blocks:
# HTTP redirect
ServerName example.com
ServerAlias *.example.com
Redirect permanent / https://www.example.com/
# HTTPS canonical host
ServerName www.example.com
SSLEngine on
# SSL certificate configuration...
# Optional: Secondary HTTPS redirect
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com$1 [R=301,L]