Automatic HTTPS configuration for Apache

Recent versions of Apache contain a module, mod_md, which will automatically obtain and renew HTTPS certificates from the Let’s Encrypt project. If you are using a supported version of Apache, TIG strongly recommends that you use this mechanism rather than manually requesting certificates from InCommon as described in “Requesting an SSL certificate”, although there are a few caveats: * Let’s Encrypt applies a rate limit across the whole mit.edu domain of 50 new domains per week, so depending on what other people are doing on campus, you might have to wait. (This limit does not apply to renewals.) * mod_md does not currently (July, 2020) support generating Elliptic Curve keys, which are nowadays preferred over RSA keys. This is expected to be rectified in the future. * If you are using Ubuntu, 18.04LTS (“Bionic”) has too old an Apache release to support mod_md. You will need to upgrade to 20.04 (“Focal”) first. * If you are sharing the same certificate between multiple services (say, a web server and an IMAP server) this is probably not the best approach, and you should obtain InCommon certificates instead.

On the positive side, Let’s Encrypt works with any domain name you can arrange to point to your server, even if it’s not a subdomain of csail.mit.edu, which makes it the only practical way to have HTTPS for example.csail.mit.edu, example.mit.edu, and example.org on the same server.

Procedure

The following steps assume you are using Apache 2.4.41 as packaged for Ubuntu 20.04LTS (“Focal”). The same concepts will apply to other operating systems but you may have to perform some of the steps manually or using other tools. If you have 2.4.42 or later, you should turn OCSP stapling on in the configuration as described in a comment below.

Fix the default server configuration

Check all of the Apache configuration files in /etc/apache2/sites-enabled for a ServerAdmin directive. Make certain that the ServerAdmin directive is present and contains your valid email address. (mod_md cannot sign up for a Let’s Encrypt account on your behalf without a valid email address.)

Enable the requisite Apache modules

sudo a2enmod md
sudo a2enmod ssl
sudo a2enmod http2

Create a configuration for the HTTPS virtual host

You will need both server-global configuration and some directives that are specific to a VirtualHost container, but in the normal case these can all go in one file, such as /etc/apache2/sites-enabled/000-ssl.conf:

# This tells Let's Encrypt who you are, and may be used to send
# notifications to you if the renewal automation breaks for some
# reason.
ServerAdmin YOUR-EMAIL-HERE@csail.mit.edu

# This is the primary server name of the certificate.  While you can
# list other names on this line, usually "auto" will do the thing you
# want -- it will find all the ServerName and ServerAlias directives
# in your server configuration and get certificates for all of them.
MDomain SERVER-NAME-HERE.csail.mit.edu auto

# This is your consent to Let's Encrypt's terms and conditions.
MDCertificateAgreement accepted

# This automatically configures your HTTP virtual hosts to redirect to
# HTTPS and sets a `Strict-Transport-Security:` HTTP header to tell
# browsers to always use HTTPS even if the user follows an `http://` link.
MDRequireHttps permanent

# Override the poor choice of `SSLCipherSuite` in the default Ubuntu
# mod_ssl configuration.  Must be all on one line.
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off

# Disable a low-security session resumption feature.
SSLSessionTickets off

# Enable HTTP/2 in addition to regular HTTP and the TLS-based ACME
# server identity verification protocol.
Protocols h2 http/1.1 acme-tls/1

# Modern HTTPS uses the server name given in the ServerName directive
# to distinguish virtual hosts.  All VirtualHost containers should
# specify the same argument (usually "*:443") and MUST have different
# ServerName directives.  Usually you only need one.
<VirtualHost *:443>
        ServerName SERVER-NAME-HERE.csail.mit.edu
        DocumentRoot /var/www/html
        # mod_md will take care of obtaining certificates via Let's Encrypt
        # so this directive is all you need in each VirtualHost container
        SSLEngine on

        # Ubuntu 20.04 focal has Apache 2.4.41, which is one release too
        # early to support OCSP stapling. If you have 2.4.42 or later,
        # uncomment the following:
        #MDStapling on
</VirtualHost>

Restart Apache and wait

sudo systemctl restart apache2
tail -f /var/log/apache2/error.log

Note that you must fully restart Apache for the new configuration to take effect; a reload is not sufficient. Wait for mod_md to log the following message to /var/log/apache2/error.log:

AH10059: The Managed Domain SERVER-NAME-HERE.csail.mit.edu has been setup and changes will be activated on next (graceful) server restart.

If mod_md fails to set itself up with Let’s Encrypt for some reason, Apache will log an error like the following:

AH10085: Init: SERVER-NAME-HERE.csail.mit.edu:443 will respond with '503 Service Unavailable' for now. There are no SSL certificates configured and no other module contributed any.

Check error.log for more information about why it failed—probably you either had an invalid ServerAdmin directive in your configuration somewhere, or else mit.edu is being rate-limited.

Restart Apache again

This step is necessary to load the newly obtained certificates into the server and start serving HTTPS.

sudo apache2ctl graceful

Testing your server

TIG recommends that you use Qualys SSL Server Test to check your server configuration for known security flaws. As of this writing, the configuration shown above is sufficient to get an “A+” grade from Qualys.