DRY in Apache HTTP & HTTPS VirtualHosts

On a number of occasions I have needed to make a site available via both HTTP and HTTPS which can result in creating two almost identical VirtualHost stanzas. The HTTPS stanza usually ends up being a copy & paste of the HTTP stanza with the SSL certificate stuff tacked on to the end. This means you generally end up with a file that is something like the following:

# file: /etc/apache2/sites-available/site.example.com.conf

<VirtualHost *:80>
    ServerName    site.example.com
    ServerAdmin   webmaster@example.com
    DocumentRoot  /var/www/site
    ErrorLog      /var/log/apache2/site-error_log
    CustomLog     /var/log/apache2/site-access_log  vhost_combined

    # ... some rewrite rules, ACLs, etc ...
</VirtualHost>

<VirtualHost *:443>
    ServerName    site.example.com
    ServerAdmin   webmaster@example.com
    DocumentRoot  /var/www/site
    ErrorLog      /var/log/apache2/site-error_log
    CustomLog     /var/log/apache2/site-access_log  vhost_combined

    # ... duplicate rewrite rules, ACLs, etc ...

    SSLEngine  On
    SSLCertificateFile     ssl/crt/wc.example.com.crt
    SSLCertificateKeyFile  ssl/key/wc.example.com.key
</VirtualHost>

This method tends to break the "don't repeat yourself" (DRY) principle and can lead to inconsistencies if you make a typo, or forget to make changes to both stanzas. One method I have found to overcome this is to make use of the Include directive.

The first step is to take all of the configuration settings that are common to both the HTTP and HTTPS stanzas and place them in a new file:

# file: /etc/apache2/sites-include/site.example.com.conf

ServerName    site.example.com
ServerAdmin   webmaster@example.com
DocumentRoot  /var/www/site
ErrorLog      /var/log/apache2/site-error_log
CustomLog     /var/log/apache2/site-access_log  vhost_combined

# ... some rewrite rules, ACLs, etc ...

Note: I generally use Debian systems which have the convention of storing VirtualHost configuration files in /etc/apache2/sites-available, so I like to keep these common setting files in /etc/apache2/sites-include.

You can then Include this common setting file in both of your VirtualHost stanzas:

# file: /etc/apache2/sites-available/site.example.com.conf

<VirtualHost *:80>
    Include  sites-include/site.example.com.conf
</VirtualHost>

<VirtualHost *:443>
    Include  sites-include/site.example.com.conf

    SSLEngine  On
    SSLCertificateFile     ssl/crt/wc.example.com.crt
    SSLCertificateKeyFile  ssl/key/wc.example.com.key
</VirtualHost>

Using this method you only need to make changes in one location (sites-include/site.example.com.conf) and they will be applied to both HTTP and HTTPS.

You can also do something similar if you use the same wildcard SSL certificate in a number of different VirtualHost files. First move the common SSL settings into a new file:

# file: /etc/apache2/ssl/site.example.com.conf

SSLEngine  On
SSLCertificateFile     ssl/crt/wc.example.com.crt
SSLCertificateKeyFile  ssl/key/wc.example.com.key

Then Include the SSL settings file in your HTTPS VirtualHost stanza:

# file: /etc/apache2/sites-available/site.example.com.conf

<VirtualHost *:80>
    Include  sites-include/site.example.com.conf
</VirtualHost>

<VirtualHost *:443>
    Include  sites-include/site.example.com.conf
    Include  ssl/wc.example.com.conf
</VirtualHost>

This can be particularly useful if you have a number of extra SSL settings that need to be configured.