Optimal Let’s Encrypt configuration

Although Let’s Encrypt certificates are free, we can use them, but we must make them give the maximum security performance to our WordPress.

If we want to get the most out of it, we will not have to use the certificate that is generated by default, but we will have to make and activate some extra configurations.

Remember that certificates are not compatible with very old browsers, but if you have users who use modern devices it should not give you a problem.

This tutorial has been created on a Clouding.io VPS. You can create your own VPS from 3€/month.

In addition, you have the possibility to create your VPS with the WordPress image in one click.

PARTNERSHIP

Installation

For this test on Ubuntu 20, we’re going to simply install an nginx and the certbot (the EFF’s let’s Encrypt certificate management tool).

snap install core && snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot

Before we forget, and for the system to update and renew the certificates when it touches, we can configure a cron that does it.

crontab -e

To whom we will tell, for example, to update the certificates every day at 06:45.

45 6 * * * certbot renew

Configuring nginx

Ignoring the configuration of nginx, let’s focus on the specific configuration of the default site.

cd /etc/nginx/sites-available/
vim default

There we will leave something as simple as this:

server {
  listen 80;
  listen [::]:80;
  server_name www.example.com example.com;
  root /var/www/html;
  index index.html;
  location / {
    try_files $uri $uri/ =404;
  }   
}

In this configuration we will indicate the domain to use, which is the main thing we will need. With this, our website should work and look good (even if it is a simple HTML).

We will check, restart and validate that nginx works.

nginx -t
systemctl restart nginx.service
systemctl status nginx.service

Creating the certificate

In order to use a Let’s Encrypt certificate, we must first register or update our account.

certbot register --email my_email@example.com --agree-tos --no-eff-email

And if you’ve used this before, you can update the data.

certbot update_account --email my_email@example.com --agree-tos --no-eff-email

Once we have the account created, we can create our certificate. The system we are going to use is that of DNS validation, which, among all the possible ones, is the most difficult to be compromised.

certbot certonly --manual --preferred-challenges dns -d example.com -d www.example.com --cert-name example.com

In the process, it will ask us to add (for the first and only time) an entry in the DNS, so that it is able to validate that we are the owners of the domain.

Please deploy a DNS TXT record under the name:

_acme-challenge.example.com.

with the following value:

77cm8TbWavyWrTp2cB9zSbHL5q8x5nFqufEpS9ykQsKNwrGc

We will add the entry in the DNS and click on continue. Once this is done, it will give us the path of the system in which our certificate is located.

/etc/letsencrypt/live/example.com/fullchain.pem

Installing the certificate

Now that we have the certificate created we can install it and put it into operation.

We will reload the nginx configuration file and add the part that makes the HTTPS work and that has the certificate activated.

cd /etc/nginx/sites-available/
vim default

We will separate the part without a certificate (which will redirect from HTTP to HTTPS) and activate the rest.

#Mandamos todo el tráfico de HTTP a HTTP
server {
  listen 80;
  listen [::]:80;
  server_name www.example.com example.com;
  return 301 https://www.example.com$request_uri;
  access_log off;
}
#Activamos el sitio con HTTPS
server {
  listen 443 ssl;
  listen [::]:443 ssl ipv6only=on;
  server_name www.example.com example.com;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
  root /var/www/html;
  index index.html;
  location / {
    try_files $uri $uri/ =404;
  }
}

By default Let’s Encrypt only uses TLSv1.2 and TLSv1.3, which are the two correct versions. In any case, we will have to make sure that this is the case.

vim /etc/letsencrypt/options-ssl-nginx.conf

And we will validate that in the corresponding line there is only that configuration.

ssl_protocols TLSv1.2 TLSv1.3;

Once this is configured, we will validate and restart nginx.

nginx -t
systemctl restart nginx.service
systemctl status nginx.service

To validate that the TLS certificate is installed and working, we can use the SSLLabs tool.

This is fine… but can we get a better score?

Validating DNS

If we want a certificate to have some importance, we can block which provider is going to issue it, something that would increase security, since not everyone could generate it.

In this case, we can limit it by DNS (all providers have their configuration, and several can be indicated, by priority).

letsencrypt.wpdanger.systems.    CAA 0 issue "letsencrypt.org"
letsencrypt.wpdanger.systems.    CAA 0 iodef "mailto:my_email@example.com"
With this we will achieve one more step.

Extending security

Until now we have a secure certificate, but we can continue to increase certain parameters.

The first of these will be to have a 4096-bit certificate instead of a 2048-bit certificate, which is the one generated by default.

certbot certonly --manual --preferred-challenges dns --key-type rsa --rsa-key-size 4096 -d example.com -d www.example.com --cert-name example.com --force-renew

And the next thing is going to be to improve the configuration of nginx to activate two elements: the OCSP and the security headers.

cd /etc/nginx/sites-available/
vim default

In which we will replace the configuration.

#Mandamos todo el tráfico de HTTP a HTTP
server {
  listen 80;
  listen [::]:80;
  server_name www.example.com example.com;
  return 301 https://www.example.com$request_uri;
  access_log off;
}
#Activamos el sitio con HTTPS
server {
  listen 443 ssl;
  listen [::]:443 ssl ipv6only=on;
  server_name www.example.com example.com;

  # TLS CERT
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

  # TLS OCSP Stapling
  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 208.67.222.222 8.8.8.8 valid=300s;
  resolver_timeout 2s;

  # Security headers
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
  add_header X-Frame-Options SAMEORIGIN;
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";

  # SITE
  root /var/www/html;
  index index.html;
  location / {
    try_files $uri $uri/ =404;
  }
}

Now that we have the new certificate and configuration, we will restart the service.

nginx -t
systemctl restart nginx.service
systemctl status nginx.service

And we will get a higher score and security.


About this document

This document is regulated by the EUPL v1.2 license, published in WP SysAdmin and created by Javier Casares. Please, if you use this content in your website, your presentation or any material you distribute, remember to mention this site or its author, and having to put the material you create under EUPL license.