2

I have a website with 20 different SSL certificates served with SNI. The current configuration file is rather long and have many duplicates, as I have 20 <VirtualHost *:443> blocks, with mostly identical values, for ServerAdmin, DocumentRoot, ErrorLog, etc.

The only different values are ServerName, ServerAlias, SSLCertificateFile, SSLCertificateKeyFile.

Is there a DRY (Don't Repeat Yourself) solution to this configuration set?

iTayb
  • 791
  • 4
  • 10
  • 25
  • Use a configuration manageent tool. – user9517 Dec 27 '16 at 17:40
  • @Hanginoninquietdesperation Automating the creation of such configuration files doesn't make them slim and pretty. It'll make the configuration easier, but will still look like a mess – iTayb Dec 27 '16 at 21:14
  • They don't have to be aesthetically pleasing - they just have to work. Using a CM system abstracts the aesthetics away from the system too. I almost never need to look at my actual config files. I just look at the code that generates them. – user9517 Dec 27 '16 at 21:26

1 Answers1

1

From apache 2.4 you can use mod_macro

Example usage:

a2enmod macro

Create a file /etc/apache2/conf-available/001-macro.conf:

<IfModule !macro_module>
  Error "mod_macro is required. To enable it run:  a2enmod macro"
</IfModule>

<Macro VHostLog $domain $port>
  LogLevel warn
  ErrorLog ${APACHE_LOG_DIR}/error_$domain_$port.log
  CustomLog ${APACHE_LOG_DIR}/access_$domain_$port.log vhost_combined
</Macro>

<Macro RedirectTo $protocol $domain>
  <If "'${well_known_enabled}' == 'On' && %{REQUEST_URI} =~ m#^/\.well-known(/|$)#">
    # Do nothing
  </If>
  <ElseIf "tolower(req('Host')) != '$domain' || tolower(%{REQUEST_SCHEME}) != '$protocol'">
    Redirect permanent / $protocol://$domain/
  </ElseIf>
</Macro>

<Macro EnableSSL>
  <IfModule !ssl_module>
    Error "mod_ssl is required. To enable it run:  a2enmod ssl"
  </IfModule>
  SSLEngine On
  SSLCertificateFile /opt/letsencrypt/${hostname}-fullchain.crt
  SSLCertificateKeyFile /opt/letsencrypt/${hostname}.key
</Macro>

<Macro DirGrantAll $dir>
  <Directory "$dir">
    Require all granted
  </Directory>
</Macro>

### VHostStandard

<Macro VHost $port $domain>
  Use VHostCustom $port $domain ${doc_root}/$domain
  Use DirGrantAll ${doc_root}/$domain
</Macro>

<Macro VHostHTTP $domain>
  Use VHostCustomHTTP $domain ${doc_root}/$domain
  Use DirGrantAll ${doc_root}/$domain
</Macro>

<Macro VHostHTTPS $domain>
  Use VHostCustomHTTPS $domain ${doc_root}/$domain
  Use DirGrantAll ${doc_root}/$domain
</Macro>

### VHostCustom

<Macro VHostCustom $port $domain $dir>
  ServerName $domain
  DocumentRoot "$dir"
  Use VHostLog $domain $port
</Macro>

<Macro VHostCustomHTTP $domain $dir>
  Use VHostCustom 80 $domain $dir
</Macro>

<Macro VHostCustomHTTPS $domain $dir>
  Use VHostCustom 443 $domain $dir
  Use EnableSSL
</Macro>

### VHostRedirect

<Macro VHostRedirect $port $server $redirect_protocol $redirect_domain>
  Use VHostCustom $port $server ${safe_doc_root}
  <Location />
    Require all granted
  </Location>
  Use RedirectTo $redirect_protocol $redirect_domain
</Macro>

<Macro VHostRedirectHTTP $server $redirect_protocol $redirect_domain>
  Use VHostRedirect 80 $server $redirect_protocol $redirect_domain
</Macro>

<Macro VHostRedirectHTTPS $server $redirect_protocol $redirect_domain>
  Use VHostRedirect 443 $server $redirect_protocol $redirect_domain
</Macro>

### VHostAlias
<Macro VHostAlias $port $server $redirect_protocol $redirect_domain>
  <VirtualHost *:$port>
    Use VHostRedirect $port $server $redirect_protocol $redirect_domain
  </VirtualHost>
</Macro>

<Macro VHostAliasHTTP $server $redirect_protocol $redirect_domain>
  Use VHostAlias 80 $server $redirect_protocol $redirect_domain
</Macro>

<Macro VHostAliasHTTPS $server $redirect_protocol $redirect_domain>
  Use VHostAlias 443 $server $redirect_protocol $redirect_domain
</Macro>

Enable the conf

a2enconf 001-macro.conf

In your VHost config for example write:

Use VHostHTTP www.example.com

Some directives are required for some of the macros above to work.

In /etc/apache2/apache2.conf:

PassEnv hostname
PassEnv doc_root
PassEnv safe_doc_root

In /etc/apache2/envvars:

export hostname=$(hostname -s)
export doc_root=/var/www/html
export safe_doc_root=/var/www/empty

Restart apache

systemctl restart apache2

This is just an example of my early experimentation. I will also check out if for example ansible would be better suited.

In the macros above I have always one certificate per hostname. Of course you need to adapt this to use different certificates on the VHosts.

See https://httpd.apache.org/docs/2.4/mod/mod_macro.html

rda
  • 1,947
  • 1
  • 13
  • 22