Blog/Let’s Encrypt with Apache and GnuTLS

From Forza's ramblings

2021-07-04: Let’s Encrypt with Apache and GnuTLS[edit | edit source]

Screenshot SSL Server Test A+.png

Let's Encrypt is today the de-facto free and open certificate authority (CA). It provides users with free TLS certificates so they can enable HTTPS on their web servers and other services that uses TLS. Let's Encrypt has really helped the Internet as a whole to move to secure HTTPS communication.

Using automated tools such as Certbot it is possible to automate requesting new TLS certificates as well as automatically renew certificates that are about to expire.

To learn more about how Let's Encrypt works, head over to

Certbot[edit | edit source]

If you have an Apache webserver, then Certbot is very easy to use. The basic command line to request a new TLS certificate would be:

# certbot --apache

This will present you a list of domains from your Apache config and asks you which one you want to enable HTTPS for.

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):

Simply select the domain you want to create and install a TLS certificate for. This will update your corresponding Apache vhosts.d/*.conf files with certificates and SSL settings:

# vhost config 

### HTTPS (with TLS/SSL) is running on port 443 ###
<VirtualHost *:443>
 DocumentRoot    /var/www/domains/
 Protocols     h2 h2c http/1.1
 H2EarlyHints  on
 RewriteEngine On
 RewriteRule ^/?w(/.*)?$ %{DOCUMENT_ROOT}/mediawiki/index.php [L]
 RewriteRule ^/?$ %{DOCUMENT_ROOT}/mediawiki/index.php [L]

 <Directory /var/www/domains/>
   ExpiresActive On
   ExpiresDefault A0
   <FilesMatch "^favicon.ico">
     ExpiresDefault "access plus 3 month"
   DirectoryIndex index.html
   Options -Indexes -FollowSymlinks
     AllowOverride All
     Require all granted

 AllowEncodedSlashes NoDecode
 <Directory /var/www/domains/>
   ExpiresActive On
   ExpiresDefault A0
   DirectoryIndex index.php
   Options -Indexes +FollowSymlinks
     AllowOverride All
     Require all granted    
   <FilesMatch "\.php$">
     SetHandler "proxy:unix:/run/php-fpm/fpm-wiki.socket|fcgi://localhost"
 <Directory /var/www/domains/>
   ExpiresActive On
   ExpiresDefault "access plus 2 months"
   AllowOverride None
   # Serve HTML as plaintext, don't execute SHTML
     AddType text/plain .html .htm .shtml .phtml
   # Don't run arbitrary PHP code.
     php_admin_flag engine off
 <Directory /var/www/domains/>
   ExpiresActive On
   ExpiresDefault "access plus 2 months"

# Certbot added config
 SSLCertificateFile /etc/letsencrypt/live/
 SSLCertificateKeyFile /etc/letsencrypt/live/
 Include /etc/letsencrypt/options-ssl-apache.conf

### HTTP (no SSL) is running on port 80 ###
<VirtualHost *:80>
 DocumentRoot    /var/www/domains/

# Certbot added config 
 RewriteEngine On
 RewriteCond %{HTTPS} off
 RewriteCond %{REQUEST_URI} !^/.well-known
 RewriteCond %{SERVER_NAME}
 RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

The file /etc/letsencrypt/options-ssl-apache.conf contains OpenSSL specific settings such as what Cipher Suites and TLS protocols that should be enabled.

Certbot with GnuTLS[edit | edit source]

Unfortunately, Certbot's Apache installer does not support mod_gnutls which uses GnuTLS instead of OpenSSL for HTTPS. The Apache installer is able to look in apache config files to determine what domain names you have. It also uses a temporary vhost definition during certificate creation process. At the end it instructs Apache to reload its configuration, enabling the new certificates.

In order to use Certbot with GnuTLS you have to use the webroot installer which instructs certbot to use a pre-existing directory in your webserver. You also need to add the certificates manually to your Apache VirtualHost config.

Using Certbot webroot installer[edit | edit source]

The Webroot installer needs the full path to your websites root. Usually this would be the DocumentRoot from you VirtualHost definition. In my case I have DocumentRoot /var/www/domains/ The command line would be:

USAGE: certbot certonly --dry-run --webroot -w <DocumentRoot> -d <domain-name> --deploy-hook "<command>"

# certbot certonly --dry-run --webroot -w /var/www/domains/ -d --deploy-hook "apache2ctl -k graceful"
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Simulating renewal of an existing certificate for
The dry run was successful.

- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps 
to enable that functionality. See for instructions.

Certbot will create the directory /var/www/domains/ from which Let's Encrypt is fetching the challenge response needed to issue the certificate.

--dry-run option is used to test the configuration and see that Let's Encrypt servers can access the .well-known directory etc. Once you see everything is working you runt the command line without it.

Apache VirtualHost configuration[edit | edit source]

You need to change two files:

  1. Your Apache vhost.d/*.conf (/etc/apache2/vhosts.d/
  2. /etc/letsencrypt/options-ssl-apache.conf

In the VirtualHost definition you need to replace

SSLCertificateFile /etc/letsencrypt/live/
SSLCertificateKeyFile /etc/letsencrypt/live/
Include /etc/letsencrypt/options-ssl-apache.conf


GnuTLSCertificateFile /etc/letsencrypt/live/
GnuTLSKeyFile /etc/letsencrypt/live/
Include /etc/letsencrypt/options-gnutls-apache.conf

Create a file /etc/letsencrypt/options-gnutls-apache.conf containing:

GnuTLSEnable on

Apache Logging[edit | edit source]

GnuTLS uses different variables for logging. If you convert from mod_ssl to mod_gnutls you may need to change any LogFormat definitions using %{SSL_PROTOCOL}x %{SSL_CIPHER}x to %{SSL_PROTOCOL}e %{SSL_CIPHER}e

LogFormat "%v %h %t \"%r\" %>s %b %{SSL_PROTOCOL}e %{SSL_CIPHER}e \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined

Automatic renewal[edit | edit source]

It is important to set up a cron job that automatically renews your certificate before it expires.

Simply create a daily cronjob as:

FILE: /etc/cron.daily/certbot-renew

/usr/bin/certbot renew  2>&1

Certbot will only renew certificates close to expiry, so it is recommended to let it run every day.

Renewal Hooks - reload Apache after renewal[edit | edit source]

A renewal hook is a script or program that certbot runs after a certificate is successfully renewed. You need to add a command that reloads the Apache config files. On most systems it would be apache2ctl -k graceful, systemctl reload apache2 or systemctl reload httpd. Check your Linux distribution manual to be sure.

FILE: /etc/letsencrypt/renewal/

version = 1.15.0
archive_dir = /etc/letsencrypt/archive/
cert = /etc/letsencrypt/live/
privkey = /etc/letsencrypt/live/
chain = /etc/letsencrypt/live/
fullchain = /etc/letsencrypt/live/

# Options used in the renewal process
account = *redacted*
rsa_key_size = 4096
renew_hook = apache2ctl -k graceful
authenticator = webroot
server =
webroot_path = /var/www/domains/

[[webroot_map]] = /var/www/domains/

Testing that HTTPS is working[edit | edit source]

You can use Qualys SSL Labs SSL Server test to check how well your server is performing. If all is OK you should receive an "A+" rating.

Screenshot SSL Server Test A+.png