Managing duplicate VirtualHost configurations in Apache for HTTP and HTTPS can become messy, especially when dealing with complex setups. The ideal solution would allow maintaining a single configuration block while handling both protocols appropriately.
Apache provides several approaches to handle this scenario without configuration duplication:
ServerName example.com
DocumentRoot /var/www/html
SSLEngine on
SSLCertificateFile /path/to/cert.pem
SSLCertificateKeyFile /path/to/key.pem
SSLCertificateChainFile /path/to/chain.pem
# Common configuration for both protocols
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
For more complex scenarios where complete separation is preferred, you can use includes:
# Main configuration file
ServerName example.com
Include /etc/apache2/sites-available/common.conf
Include /etc/apache2/sites-available/ssl.conf
- Test configuration with
apachectl configtest
before reloading - HTTP/2 requires explicit SSL configuration
- Some rewrite rules may need protocol-specific conditions
- Consider HSTS headers for HTTPS-only sites
Here's a complete production-ready example with redirects:
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Header always set Strict-Transport-Security "max-age=63072000"
# Force HTTPS redirect
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Common configuration
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
Managing separate VirtualHost configurations for HTTP and HTTPS in Apache can become messy, especially when dealing with complex setups. Many administrators find themselves maintaining nearly identical configurations in two separate blocks, which violates the DRY (Don't Repeat Yourself) principle and increases the chances of configuration drift.
The most elegant solution is to use Apache's IfDefine
directive combined with the SSL
variable that Apache sets automatically when SSL is enabled:
ServerName example.com
DocumentRoot /var/www/html
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
SSLCertificateChainFile /etc/ssl/certs/example.com.ca-bundle
# Common configuration for both protocols
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Additional directives...
Another approach is to check for the SSL module's presence:
ServerName example.com
SSLEngine on
# SSL configuration here
# Shared configuration
When using this approach:
- Make sure to include both ports (
*:80 *:443
) in the VirtualHost declaration - All non-SSL directives will apply to both HTTP and HTTPS connections
- For more granular control, you might still need separate VirtualHosts
- Test your configuration with
apachectl configtest
before reloading
If you need to redirect HTTP to HTTPS while keeping a single VirtualHost:
ServerName example.com
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
SSLEngine on
# SSL configuration
While this unified approach reduces configuration complexity, be aware that:
- All requests (HTTP and HTTPS) will go through the same VirtualHost processing
- Conditional checks add minimal overhead
- For high-traffic sites, separate VirtualHosts might be preferable