Lets Encrypt - Free Domain Verified certificates for everyone.

I've begun the process of moving all the sites I host to HTTPS. I was lucky enough to get a Beta Program invitation for the Let's Encrypt project. I used their ACME client to verify domain control and issue a certificate. I was impressed by how easy the process was. The project is scheduled to move into general availability in the middle of November 2015.

I've been participating in the community support section of the LetsEncrypt.org site for a few weeks now and have seen a few issues from people trying to issue certificates who were not "technical" people. While the ACME client can do many of the technical parts of the process, such as configuring Apache, verifying the domain, getting the certificates, and reconfigure Apache to use them, the process can be kind of intimidating. One of the first issue I saw was users trying to use the ACME client to get certificates for domains the own but host on shared hosting systems. Since the ACME client requires command line access, as of now, I don't see any reasonable way for these people to use an automated certificate issuance system.

After experimenting with the system I've come up with my best practices for issuing certificates, installing them, and serving them. I'll detail my process here.

90 Days...?

LetsEncrypt certificates are only valid for 90 days! So automating the renewal process is a must. I am not going to cover that in my guide here, as I haven't cemented my process yet. Once I have renewed my certificates and am comfortable with my process I'll create an update post. I'm not going to get into a debate as to why 90 days as a opposed to a year, as this issue has been hashed out over and over on the LetsEncrypt community forums.

Issuing a certificate

The LetsEncrypt client's official documentation is available here. There are many options and greater levels of automation. I chose to use some custom configuration options to better fit into my environment.

As my configuration is a bit more complicated I created the needed certs using "certonly":

./letsencrypt-auto certonly -c /etc/letsencrypt/cli.ini -d example.com -d www.example.com

This command will verify ownership/control of example.com, and assuming that your Let's Encrypt client is running at the IP address that the DNS A Record points at, should pass verification for both domains listed, and create a certificate for example.com with a Subject Alternative Name record for www.example.com. I am using a config file flag (-c) to specify a custom config file to use. This allows me to run the same commands over and over needing only to specify the domains I wish to get certs for on the command line. I'll discuss the config file contents later on.

Webroot Authentication

I chose to use the webroot authentication method which will verify the presence of a file that is interactively created by the Lets Encrypt client. These files will be served by the existing web server, meaning that to verify the domain and issue the cert there is no need to take the webserver offline. To do this from the command line you need to specify the authenticator flag (--authenticator webroot). Also required is the path to the actual webroot of your live site (--webroot-path /var/www/html), your path may vary depending on your configuration. During the verification process the Let Encrypt client will write files to {webroot-path}/.well-known/acme-challenge/{some-random-generated-garbage-here}

My first few passes at using the webroot authentication failed, indicating a 403 Forbidden error. After some trouble shooting I found that this was being caused by the Drupal default .htaccess file that lives in my webroot. The Drupal .htaccess file prevents Apache from serving "hidden" files and directories, which is a good security measure to take, however this prevented the ".well-known" folder from being available. I was able to correct this issue using an overriding .htaccess in the ".well-known" directory. The .htaccess file I'm using is here:

Re-running the command to verify and issue the cert now went through fine.

Configuration File

My configuration file is pretty simple, covering only the commands I'll be using every time I issue a certificate on this server.

The first thing I do (line 5) is to override the default key size that Lets Encrypt uses too 4096, while this is currently entirely optional, a larger key should be a greater challenge to crack and will one day be considered the norm.

Next is setting the ACME server you wish to authenticate against. The value in my example will not function. As Lets Encrypt is currently in a closed Beta, I'm leaving the production server address out of the example. If you get a Beta invite, or once the project has reached general availability this server address will be made public.

The email flag may not actually be required here, other than the very first time, but I include it on all requests for now for warm fuzzies.

The next two lines specify the authentication method (webroot) and the path to the webroot-path. I went over these values above.

As my server configuration is almost always evolving I am using the --duplicate true command. This allows getting a certificate that duplicates an existing one.

The last line is currently required for issuing certs during the closed beta. Although a similar line may be required later on, such as "--agree-tos".

With the config file, any flag that is supported by the application should be able to be included in the config file.

A Single webroot path

To make things easier I am using the same webroot path for all sites I host on my servers. I created a new location, "/var/www/LEwebroot", and inside it copied the ".well-known" directory from a previous verification, including my custom .htaccess file mentioned above.

Once the new webroot is established I created a letsencrypt.conf file in my "/etc/apache2/sites-available" directory.

Enabling this using:

sudo a2ensite letsencrypt
sudo service apache2 reload

Now anytime the ".well-known" sub-directory is requested on any of the vhosts on this server, the one in my LEwebroot folder will be served instead. The only thing left to do is to modify the webroot-path directive used in my config file to match the new Alias webroot (webroot-path = /var/www/LEwebroot).

Now every time I request a certificate for a site hosted on this server, the only thing I need to specify is the domain(s) I wish to verify. A big time saver.

Configure Apache to serve the sites over HTTPS.

The Lets Encrypt client is capable of modifying your Apache configuration (nginx coming soon) to use the newly generated certificates. I tried it once, and it broke things. For most basic server (out-of-the-box) setups it looks like this would work perfectly, but as mine is a bit more complex, I'm going to only use manual configuration of Apache. This setup process is only needed once, as once the certificates are issued they are located in the same directory/path always. Even after a renewal, Apache should only need to be reloaded (sudo service apache reload) and no configuration changes would need to be made.

Below is an example of the configuration file I'm using.

This can be included as a separate file or in the same file that is currently serving your current HTTP site. If you are not already hosting any sites over HTTPS you may need to modify your ports.conf to bind to port 443 and enable mod_ssl.

Once your changes are completed check that you haven't messed things up using "apachectl -t", and look for "Syntax OK".

Activate your new site by reloading Apache, "sudo service apache2 reload". And test. These settings should be enough to get an A+ rating from SSLLabs' test.

A Plus results for Copy.MX domain

OCSP Stapling

While not required, using OCSP Stapling provides an avenue for more private browsing for your site's visitors, I suggest activating it.

OCSP stapling, formally known as the TLS Certificate Status Request extension, is an alternative approach to the Online Certificate Status Protocol (OCSP) for checking the revocation status of X.509 digital certificates. It allows the presenter of a certificate to bear the resource cost involved in providing OCSP responses by appending ("stapling") a time-stamped OCSP response signed by the CA to the initial TLS Handshake, eliminating the need for clients to contact the CA.

OCSP stapling. (2015, August 14). In Wikipedia, The Free Encyclopedia. Retrieved 18:32, November 7, 2015, from https://en.wikipedia.org/w/index.php?title=OCSP_stapling&oldid=676060119

I found many guides on the web regarding activating OCSP Stapling in Apache, and nearly all of them were WRONG. Here is my current working OCSP Stapling configuration for Apache 2.4. Many of these incorrect guides instructed setting OCSP Stapling "SSLUseStapling On" in the individual VHost files, but this simply will not work.

To activate OCSP Stapling you need to edit your ssl.conf folder found at "/etc/apache2/mods-available/ssl.conf". Adding the following lines will enable OCSP Stapling for ALL SITES running on this server.

If there are sites that should not use stapling, as the CA used doesn't support them or they are using self-signed certificates, you should modify their VHost file and add "SSLUseStapling Off".

Once the above changes are made run "apachectl -t", and look for "Syntax OK". Then reload Apache, "sudo service apache2 reload". Your sites should now support OSCP Stapling.

You can verify this through the use of SSL Labs' test again, or on the command line using the OpenSSL command.

openssl s_client -connect example.com:443  -servername example.com -tls1 -tlsextdebug -status | grep 'OCSP'

You should see a response of "OCSP Response Status: successful (0x0)" indicating that everything is working correctly. If you leave off the "| grep 'OCSP'" you can inspect the entire OCSP response, but I left it off for the sake of brevity.

SSL Labs test showing OCSP Stapling working