Instalar y renovar un certificado de Let's Encrypt en Nginx

Escrito por el , actualizado el .
planeta-codigo seguridad software software-libre web
Enlace permanente Comentarios

Let’s Encrypt es una entidad que emite certificados TLS/SSL que son reconocidos como de confianza por los navegadores web. Usando esta entidad de certificación es posible obtener y renovar un certificado TLS/SSL de forma automatizada, rápida y sin coste alguno.

Let's Encrypt

Google ha anunciado que su buscador va a considerar el uso del protocolo seguro HTTPS como un criterio de SEO y posicionamiento en la lista de resultados, posicionando mejor aquellas páginas web que usen el protocolo seguro. Además, el navegador Chrome va a advertir al usuario para algunas páginas que usen solo HTTP que esas páginas son inseguras. Por estos motivos y para mayor seguridad y privacidad del usuario es conveniente usar el protocolo seguro HTTPS.

El mayor inconveniente de usar el protocolo seguro HTTPS es que es necesario un certificado firmado por una autoridad de confianza instalada en el navegador del usuario. Hasta ahora había que comprar el certificado que puede llegar a tener un coste de más de 100 €, instalarlo en el servidor y renovarlo antes de su fecha de expiración. Tareas quizá manuales por tanto tediosas y propensas a que surjan errores o se nos olvide hacer la renovación del certificado sobre todo si son múltiples los certificados a gestionar.

Para mejorar la seguridad en la web y facilitar la administración de certificados hace un tiempo se creó una entidad Let’s Encrypt asociado a la Linux Foundation con la que es posible automatizar la obtención y renovación de un certificado TLS/SSL firmado por una autoridad de confianza para los navegadores. Además Let’s Encrypt permite obtener un certificado sin ningún coste, de forma gratuita.

Los pasos para usar en un servidor web un certificado de Let’s Encrypt son los siguientes. Primero hay que instalar el paquete certbot según la distribución de GNU/Linux, en Arch Linux:

1
2
# pacman -S certbot

pacman.sh

En el proceso de obtención del certificado demostraremos que somos los propietarios del sitio web a certificar. Usando nginx como servidor web, iniciado y el dominio a certificar con la opción -d se usa el siguiente comando:

1
2
# certbot certonly --webroot -w /usr/share/nginx/html -d smaug.l5.ca

certbot.sh

El certificado obtenido tiene una fecha de expiración de únicamente tres meses periodo antes del cual hay que renovarlo. Para hacer la renovación hay que usar el comando:

1
2
# certbot renew

certbot-renew.sh

La renovación del certificado se realiza cuando queda poco tiempo para que expire, unos 30 días, el siguiente comando permite comprobar antes si la configuración es correcta para realizar la renovación.

1
2
# certbot renew --dry-run

certbot-renew-dry-run.sh

La clave privada y certificado que Let’s Encrypt genera una vez el dominio se ha validado se ubican en el directorio /etc/letsencrypt/live/ con una carpeta por cada dominio. También se puede ver desde la linea de comandos los certificados existentes y sus fechas de expiración.

1
2
# ls /etc/letsencrypt/live/smaug.l5.ca
cert.pem  chain.pem  fullchain.pem  privkey.pem
key-cert.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ sudo certbot certificates
[sudo] password for raspberrypi: 
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Found the following certs:
  Certificate Name: smaug.l5.ca
    Domains: smaug.l5.ca
    Expiry Date: 2017-10-21 09:18:00+00:00 (VALID: 70 days)
    Certificate Path: /etc/letsencrypt/live/smaug.l5.ca/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/smaug.l5.ca/privkey.pem
-------------------------------------------------------------------------------
certbot-certificates.sh

Dado el relativo poco tiempo de validez de los certificados es recomendable automatizar la renovación empleando una expresión cron. La utilidad certbot solo hace la renovación del certificado cuando queda menos de un més para su expiración aunque se programe su ejecución en este caso cada 6 horas y en un minuto aleatorio que Let’s Encrypt recomienda para que todos los usuarios no programen sus renovaciones al mismo tiempo:

1
2
3
$ sudo su
# crontab -e
0 */6 * * * sleep ${RANDOM:0:2}m ; certbot renew --quiet --renew-hook "systemctl restart nginx.service"
cron.sh

Una vez que se ha renovado el certificado hay que reiniciar el servidor web para que lo utilice y para ello está el parámetro --renew-hook que ejecuta un comando cuando se produce una renovación. En el ejemplo anterior está el comando para reiniciar el servicio de nginx con el sistema gestión de procesos de systemd.

Let’s Encrypt con certbot comprueba si somos el propietario de un sitio web instalando en el servidor web un archivo que posteriormente antes de generar el certificado lo valida. Este archivo para nginx se ubica en el directorio /usr/share/nginx/html/.well-known/acme-challenge/ y ha de estar accesible desde internet con el protocolo HTTP en la dirección /.well-known/acme-challenge/ del servidor web.

La siguiente configuración del servidor web nginx redirige todo el tráfico usando el protocolo HTTPS excepto el contenido del directorio /.well-known/acme-challenge/ que queda accesible por HTTP.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
worker_processes  1;

events {
  worker_connections 64;
}

http {
  include       mime.types;
  default_type  application/octet-stream;

  sendfile        on;
  #tcp_nopush     on;

  keepalive_timeout  65;

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  server {
    listen       80;
    server_name  localhost smaug.l5.ca;

    location /.well-known/ {
      allow all;
      alias /usr/share/nginx/html/.well-known/;
    }

    location / {    
      return 301 https://$host$request_uri;
    }
  }

  server {
    listen       443 ssl http2 default_server;
    server_name  localhost smaug.l5.ca;

    ssl_certificate      /etc/letsencrypt/live/smaug.l5.ca/cert.pem;
    ssl_certificate_key  /etc/letsencrypt/live/smaug.l5.ca/privkey.pem;

    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers   HIGH:!aNULL:!MD5;
    ssl_session_cache   shared:SSL:1m;
    ssl_session_timeout 3m;

    location / {
      root   /usr/share/nginx/html;
      index  index.html index.htm;
    }
  }
}
nginx.conf

Y este es el resultado al acceder con el navegador al sitio web que tengo instalado en una Raspberry Pi accesible desde internet con un dominio de FreeDNS:

Sitio web con certificado de Let's Encrypt Sitio web con certificado de Let's Encrypt

Sitio web con certificado de Let's Encrypt

En la documentación del proyecto de Let’s Encrypt hay explicaciones más detalladas sobre como funciona, límites de uso, como usarlo y varias guías según el servidor web y distribución GNU/Linux.


Comparte el artículo: