Read in 5 minutes

last updated 

Secure Apache with Let's Encrypt on Debian 9

Let’s Encrypt is a certificate authority created by the Internet Security Research Group (ISRG). It provides free SSL certificates via fully automated process designed to eliminate manual certificate creation, validation, installation and renewal.

Certificates issued by Let’s Encrypt are are valid for 90 days from the issue date and trusted by all major browsers today.

This tutorial will guide you through the process of obtaining a free Let’s Encrypt using the certbot tool on Debian 9. We’ll also show how to configure Apache to use the new SSL certificate and enable HTTP/2.

Prerequisites

Ensure that you have met the following prerequisites before continuing with this tutorial:

  • Have a domain name pointing to your server public server IP. In this tutorial we will use example.com.
  • Have Apache installed by following these instructions
  • An apache virtual host for your domain. You can follow these instructions for details on how to create one.

Install Certbot

Certbot is a fully featured and easy to use tool that can automate the tasks of obtaining and renewing Let’s Encrypt SSL certificates. The certbot package is included in the default Debian repositories.

Update the packages list and install the certbot package using the following commands:

sudo apt update
sudo apt install certbot

Generate Strong Dh (Diffie-Hellman) Group

Diffie–Hellman key exchange (DH) is a method of securely exchanging cryptographic keys over an unsecured communication channel.

To generate a new set of 2048 bit DH parameters run:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

If you like you can change the size up to 4096 bits but in that case the generation may take more than 30 minutes depending on the system entropy.

Obtaining a Let’s Encrypt SSL certificate

To obtain an SSL certificate for our domain we’re going to use the Webroot plugin that works by creating a temporary file for the requested domain in the ${webroot-path}/.well-known/acme-challenge directory and the Let’s Encrypt validation server makes HTTP requests to validate that the DNS for the requested domain resolves to the server where certbot runs.

To make it more simple we’re going to map all HTTP requests for .well-known/acme-challenge to a single directory, /var/lib/letsencrypt.

The following commands will create the directory and make it writable for the Apache server.

sudo mkdir -p /var/lib/letsencrypt/.well-known
sudo chgrp www-data /var/lib/letsencrypt
sudo chmod g+s /var/lib/letsencrypt

To avoid duplicating code create the following two configurations snippets:

/etc/apache2/conf-available/letsencrypt.conf
Alias /.well-known/acme-challenge/ "/var/lib/letsencrypt/.well-known/acme-challenge/"
<Directory "/var/lib/letsencrypt/">
    AllowOverride None
    Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
    Require method GET POST OPTIONS
</Directory>
/etc/apache2/conf-available/ssl-params.conf
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder On
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
# Requires Apache >= 2.4
SSLCompression off
SSLUseStapling on
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
# Requires Apache >= 2.4.11
SSLSessionTickets Off

SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem" 

The snippet above is using the chippers recommended by Cipherli.st, enables OCSP Stapling, HTTP Strict Transport Security (HSTS) and enforces few security‑focused HTTP headers.

Before enabling the configuration files, make sure both mod_ssl and mod_headers are enabled by issuing:

sudo a2enmod ssl
sudo a2enmod headers

Enable the HTTP/2 module which will make your sites faster and more robust:

sudo a2enmod http2.

Enable the SSL configuration files by running the following commands:

sudo a2enconf letsencrypt
sudo a2enconf ssl-params

Reload the Apache configuration for changes to take effect:

sudo systemctl reload apache2

Use the Certbot tool with the webroot plugin to obtain the SSL certificate files :

sudo certbot certonly --agree-tos --email [email protected] --webroot -w /var/lib/letsencrypt/ -d example.com -d www.example.com

If the SSL certificate is successfully obtained, certbot will print the following message:

IMPORTANT NOTES:
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will
   expire on 2019-01-17. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot again. To
   non-interactively renew *all* of your certificates, run "certbot
   renew"
 - If you lose your account credentials, you can recover through
   e-mails sent to [email protected]
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

Now that you have the certificate files, edit your domain virtual host configuration as follows:

/etc/apache2/sites-available/example.com.conf
<VirtualHost *:80> 
  ServerName example.com
  ServerAlias www.example.com

  Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
  ServerName example.com
  ServerAlias www.example.com

  Protocols h2 http:/1.1

  <If "%{HTTP_HOST} == 'www.example.com'">
    Redirect permanent / https://example.com/
  </If>

  DocumentRoot /var/www/example.com/public_html
  ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
  CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined

  SSLEngine On
  SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

  # Other Apache Configuration

</VirtualHost>

With the configuration above we are forcing HTTPS and redirecting from www to non www version. Fell free to adjusts the configuration according to your needs.

Reload the Apache service for changes to take effect:

sudo systemctl reload apache2

Open your website using https:// you’ll notice a green lock icon.

If you test your domain using the SSL Labs Server Test, you’ll get an A+ grade as shown bellow:

Auto-renewing Let’s Encrypt SSL certificate

Let’s Encrypt’s certificates are valid for 90 days. To automatically renew the certificates before they expire, the certbot package creates a cronjob which runs twice a day and will automatically renew any certificate 30 days before its expiration.

Once the certificate is renewed we also have to reload the Apache service. Append --renew-hook "systemctl reload apache2" to the /etc/cron.d/certbot file so it looks like the following:

/etc/cron.d/certbot
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "systemctl reload apache2"

To test the renewal process, use the certbot --dry-run switch:

sudo certbot renew --dry-run

If there are no errors, it means that the renewal process was successful.

Conclusion

In this tutorial, you used the Let’s Encrypt client, certbot to obtain SSL certificates for your domain. You have also created Apache snippets to avoid duplicating code and configured Apache to use the certificates. At the end of the tutorial you have set up a cronjob for automatic certificate renewal.

If you want to learn more about the Certbot script, their documentation is a good starting point.