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 https://letsencrypt.org/how-it-works/

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?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: tnonline.net
2: wiki.tnonline.net
3: www.tnonline.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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:

# wiki.tnonline.net vhost config 

### HTTPS (with TLS/SSL) is running on port 443 ###
<VirtualHost *:443>
 ServerName      wiki.tnonline.net
 DocumentRoot    /var/www/domains/wiki.tnonline.net/htdocs/
 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/wiki.tnonline.net/htdocs>
   ExpiresActive On
   ExpiresDefault A0
   <FilesMatch "^favicon.ico">
     ExpiresDefault "access plus 3 month"
   </FilesMatch>
   DirectoryIndex index.html
   Options -Indexes -FollowSymlinks
     AllowOverride All
     Require all granted
 </Directory>

 AllowEncodedSlashes NoDecode
 <Directory /var/www/domains/wiki.tnonline.net/htdocs/mediawiki>
   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"
   </FilesMatch>
 </Directory>
 <Directory /var/www/domains/wiki.tnonline.net/htdocs/mediawiki/images>
   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>
 <Directory /var/www/domains/wiki.tnonline.net/htdocs/mediawiki/resources/assets>
   ExpiresActive On
   ExpiresDefault "access plus 2 months"
 </Directory>

# Certbot added config
 SSLCertificateFile /etc/letsencrypt/live/wiki.tnonline.net/fullchain.pem
 SSLCertificateKeyFile /etc/letsencrypt/live/wiki.tnonline.net/privkey.pem
 Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>

### HTTP (no SSL) is running on port 80 ###
<VirtualHost *:80>
 ServerName      wiki.tnonline.net
 DocumentRoot    /var/www/domains/wiki.tnonline.net/htdocs/

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

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/wiki.tnonline.net/htdocs/. 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/wiki.tnonline.net/htdocs -d wiki.tnonline.net --deploy-hook "apache2ctl -k graceful"
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Simulating renewal of an existing certificate for wiki.tnonline.net
The dry run was successful.

NEXT STEPS:
- 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 https://certbot.org/renewal-setup for instructions.

Certbot will create the directory /var/www/domains/wiki.tnonline.net/htdocs/.well-known/acme-challenge 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/wiki.tnonline.net.conf)
  2. /etc/letsencrypt/options-ssl-apache.conf

In the VirtualHost definition you need to replace

SSLCertificateFile /etc/letsencrypt/live/wiki.tnonline.net/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/wiki.tnonline.net/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf

with

GnuTLSCertificateFile /etc/letsencrypt/live/wiki.tnonline.net/fullchain.pem
GnuTLSKeyFile /etc/letsencrypt/live/wiki.tnonline.net/privkey.pem
Include /etc/letsencrypt/options-gnutls-apache.conf

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

GnuTLSEnable on
GnuTLSPriorities PFS:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2:+VERS-DTLS1.2:-GROUP-ALL:+GROUP-X25519:+GROUP-X448:+GROUP-SECP521R1:+GROUP-SECP384R1:+GROUP-SECP256R1:-SHA1:-MD5:-AES-256-CBC:-AES-256-CCM:-AES-128-CBC:-AES-128-CCM:-CIPHER-ALL:+CHACHA20-POLY1305:+AES-256-GCM:+AES-128-GCM:+SHA384:+SHA256:+AES-256-GCM:+ECDHE-ECDSA:+ECDHE-RSA:%SERVER_PRECEDENCE

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

#!/bin/bash
/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/wiki.tnonline.net.conf

version = 1.15.0
archive_dir = /etc/letsencrypt/archive/wiki.tnonline.net
cert = /etc/letsencrypt/live/wiki.tnonline.net/cert.pem
privkey = /etc/letsencrypt/live/wiki.tnonline.net/privkey.pem
chain = /etc/letsencrypt/live/wiki.tnonline.net/chain.pem
fullchain = /etc/letsencrypt/live/wiki.tnonline.net/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = *redacted*
rsa_key_size = 4096
renew_hook = apache2ctl -k graceful
authenticator = webroot
server = https://acme-v02.api.letsencrypt.org/directory
webroot_path = /var/www/domains/wiki.tnonline.net/htdocs

[[webroot_map]]
wiki.tnonline.net = /var/www/domains/wiki.tnonline.net/htdocs


Testing that HTTPS is working[edit | edit source]

You can use Qualys SSL Labs SSL Server test https://www.ssllabs.com/ssltest/index.html to check how well your server is performing. If all is OK you should receive an "A+" rating.

Screenshot SSL Server Test A+.png