Apache's default behavior of routing unmatched host headers to the first defined VirtualHost creates security and operational concerns. When implementing multi-tenant hosting solutions, this can lead to unintended content exposure or configuration leaks.
The correct approach involves creating a catch-all VirtualHost that returns HTTP 444 (Nginx-style connection drop) or 403 Forbidden:
# /etc/apache2/sites-available/000-catchall.conf
ServerName invalid.host
ServerAlias *
RewriteEngine On
RewriteRule ^ - [R=403,L]
# Alternative silent drop:
#
# Require all denied
#
For this to work effectively:
- The catch-all must be the first loaded VirtualHost
- NameVirtualHost directive must be enabled
- Individual VirtualHosts should explicitly declare ServerName
Here's a complete configuration for a secure multi-host setup:
# Main configuration
Listen 80
NameVirtualHost *:80
# Default catch-all (must be first)
ServerName invalid.host
ServerAlias *
DocumentRoot /var/www/empty
Require all denied
ErrorLog ${APACHE_LOG_DIR}/invalid-host.log
CustomLog ${APACHE_LOG_DIR}/invalid-host-access.log combined
# Valid host 1
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example
# Additional configuration...
# Valid host 2
ServerName api.example.com
DocumentRoot /var/www/api
# Additional configuration...
For enhanced security:
- Implement mod_rewrite rules to log invalid access attempts
- Consider rate-limiting for repeated invalid requests
- Monitor the invalid-host-access.log for scanning attempts
Some administrators prefer to redirect invalid hosts instead of blocking:
ServerName invalid.host
ServerAlias *
Redirect 301 / https://valid-primary-domain.com
Apache's default behavior of routing undefined Host headers to the first VirtualHost can create security and management headaches. When you need strict hostname enforcement, here's how to properly implement it:
The most reliable method involves creating a catch-all VirtualHost that returns HTTP 444 (Nginx-style connection drop) or 403 Forbidden:
ServerName default-catch-all
Require all denied
ErrorLog ${APACHE_LOG_DIR}/invalid_host.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/invalid_host_access.log combined
# Your legitimate vhosts come AFTER the catch-all
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example
For a more Nginx-like behavior where connections are simply closed:
RewriteEngine On
RewriteCond %{HTTP_HOST} !^example\.com$ [NC]
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^ - [R=444]
- Ensure your catch-all VirtualHost is the FIRST defined vhost in your config
- For SSL configurations, duplicate this setup on port 443
- Consider logging invalid requests for security monitoring
- Test with:
curl -H "Host: bogus.example" http://yourserver
Here's a complete configuration handling both HTTP and HTTPS:
# Catch-all for HTTP
ServerName invalid-host
Redirect 403 /
ErrorLog ${APACHE_LOG_DIR}/invalid_host_error.log
CustomLog ${APACHE_LOG_DIR}/invalid_host_access.log combined
# Catch-all for HTTPS
ServerName invalid-host
SSLEngine on
# Your SSL cert paths here
SSLProtocol all -SSLv2 -SSLv3
Redirect 403 /
ErrorLog ${APACHE_LOG_DIR}/invalid_ssl_host_error.log
CustomLog ${APACHE_LOG_DIR}/invalid_ssl_host_access.log combined
# Legitimate vhosts
ServerName example.com
Redirect permanent / https://example.com/
ServerName example.com
SSLEngine on
# SSL config here...
DocumentRoot /var/www/example