When configuring Apache for multi-tenant applications with custom domains, the wildcard ServerAlias (*) is both a blessing and a curse. While it elegantly handles unlimited subdomains, it creates conflicts when you need to host other applications on the same server.
The typical wildcard virtual host configuration looks like this:
ServerName primary.example
ServerAlias * *.primary.example www.primary.example
DocumentRoot /path/to/primary/app
# Other directives...
The real problem emerges when you need to exclude certain domains from this catch-all:
- Admin interfaces (admin.example)
- API endpoints (api.example)
- Marketing sites (marketing.example)
- Legacy domains (oldapp.example)
Apache processes VirtualHost blocks in configuration file order, with the first matching ServerName/ServerAlias winning:
# Specific domains first
ServerName excluded1.example
ServerAlias www.excluded1.example
DocumentRoot /path/to/other/app
# Other directives...
# Catch-all comes LAST
ServerName primary.example
ServerAlias * *.primary.example
# Original configuration...
For more dynamic control, implement domain checks in your catch-all VirtualHost:
ServerName primary.example
ServerAlias * *.primary.example
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(excluded1|excluded2|admin)\. [NC]
RewriteRule ^ - [L,R=404]
# Original configuration...
For better maintainability with many exclusions:
# In main Apache config
IncludeOptional sites-enabled/excluded-*.conf
Include sites-enabled/wildcard.conf
Then create separate files for excluded domains in sites-enabled/
- Keep the exclusion list optimized - regex patterns can be expensive
- Consider DNS-level filtering for large-scale deployments
- Benchmark with ab -n 10000 -c 100 http://test.domain/
For truly dynamic domain management, consider integrating with your application:
ServerName primary.example
ServerAlias *
RewriteEngine On
RewriteMap excluded-domains "dbm:/path/to/domain-map.db"
RewriteCond ${excluded-domains:%{HTTP_HOST}|NOT_FOUND} !NOT_FOUND
RewriteRule ^ - [L,R=404]
# Original configuration...
When configuring Apache2 for multi-tenant applications that need to support custom domains, many developers use wildcard ServerAlias configurations like this:
ServerName example.com
ServerAlias * *.example.com
# Other configurations...
While the wildcard (*) works perfectly for catching all undefined domains, it creates conflicts when you need to:
- Host other independent applications on the same server
- Maintain admin or staging subdomains
- Support legacy domains during migration
Apache processes VirtualHosts in order of specificity. Place your exceptions before the wildcard VirtualHost:
ServerName special-app.com
DocumentRoot /var/www/special
# Other configs for this specific domain
ServerName example.com
ServerAlias * *.example.com
# Wildcard config
For more complex exclusions, use mod_rewrite with regex patterns:
ServerName example.com
ServerAlias *
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(admin|staging|legacy)\.example\.com$ [NC]
RewriteRule ^ - [L]
# Rest of your config
For mission-critical exclusions, consider using separate IP addresses:
ServerName critical-app.com
# Special config
ServerName example.com
ServerAlias *
# Wildcard config
For production environments, I recommend combining methods:
# 1. Specific domains first
ServerName admin.example.com
# Config
# 2. Regex exclusions
ServerName example.com
ServerAlias *
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(staging|dev)\. [NC]
RewriteRule ^ - [L]
# Main config
Always verify your setup with:
apachectl configtest
apachectl -S
The second command will show you how Apache is actually resolving your domains to VirtualHosts.