Instalar un certificado SSL de Let’s Encrypt en Debian 8 (Jessie) con Apache 2.4

En este post voy a explicar cómo instalar un certificado SSL de Let’s Encrypt en Debian 8 (Jessie) con Apache 2.4. Si estás buscando cómo instalar un certificado SSL de Let’s Encrypt en Debian 7 (Wheezy) con Apache 2.2 puedes encontrar un tutorial en este enlace.

Si dispongo de acceso por shell y permisos de administración, en la web de Let’s Encrypt recomiendan hacerlo a través del cliente Certbot. En esta web selecciono el servidor web y el sistema operativo donde voy a instalar el certificado y me dirige a una guía de instalación.

A continuación aparece una guía paso a paso de cómo llevar a cabo la instalación.

En este tutorial lo voy a hacer de una forma más “artesana”, para ir viendo los pasos seguidos.

Lo primero que hago es añadir el repositorio de los backports, donde se encuentra el software de Let’s Encrypt para Debian 8 y Apache 2

sudo echo 'deb http://ftp.debian.org/debian jessie-backports main' >>  /etc/apt/sources.list.d/backports.list

A continuación actualizo los paquetes

sudo apt-get update

Instalo el paquete desde backports

sudo apt-get install python-certbot-apache -t jessie-backports

Ejecuto el comando de creación de los certificados

certbot certonly --webroot -w /var/www/midominio.com/www/ -d www.midominio.com -d midominio.com

Si tenemos distintas rutas en el servidor para los subdominios hay que indicarlo adecuadamente:

certbot certonly --webroot -w /var/www/midominio.com/magento/ -d www.midominio.com -d midominio.com -w /var/www/midominio.com/wordpress/ -d blog.midominio.com

donde:

  • /var/www/midominio.com/www/ es la ruta base del sitio web para el que quiero asegurar la comunicación.
  • www.midominio.com es uno de los dominios para los que quiero crear el certificado.
  • midominio.com es otro de los dominios para los que quiero crear el certificado. En este caso es el anterior sin las “www”, situación habitual en la administración de sistemas.

El mismo certificado vale para ambos dominios. Let’s Encrypt tiene un límite de 100 dominios.

Aparece una pantalla azul en la que el programa ejecuta una serie de comandos

Si todo funciona correctamente, el programa muestra el siguiente texto por consola

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
 /etc/letsencrypt/live/midominio.com/fullchain.pem. Your cert
 will expire on 2017-04-20. 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 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

Es importante tener claro que este modo de generación del certificado (plugin webroot) trabaja creando un archivo temporal para cada uno de los dominios solicitados en la ruta

${directorio-raiz-del-dominio}/.well-known/acme-challenge

A continuación el servidor de validación de Let’s Encrypt realiza peticiones HTTP para validar los DNS para cada uno de los dominios solicitados mediante el comando “certbot”.

Hay que tener cuidado si en la configuración del host virtual están denegados los archivos o directorios que empiezan por punto “.”, ya que no se podrá acceder desde fuera a este directorio. También es importante comprobar que el firewall permita la comunicación con los servidores de Let’s Encrypt.

Si consulto el directorio /etc/letsencrypt/live/midominio.com/

ls /etc/letsencrypt/live/midominio.com/

veo que certbot ha creado 4 archivos:

  • cert.pem: el certificado de los dominios.
  • chain.pem: el certificado de la cadena de Let’s Encrypt.
  • fullchain.pem: los dos certificados anteriores combinados.
  • privkey.pem: la clave privada de mi certificado.

Realmente son enlaces simbólicos a 4 archivos existentes en el directorio /etc/letsencrypt/archive/midominio.com/ . Si lo consulto

ls /etc/letsencrypt/archive/midominio.com/

veo que los cuatro archivos

  • cert1.pem
  • chain1.pem
  • fullchain1.pem
  • privkey1.pem

son los mismos que los nombres de los enlaces simbólicos pero su nombre acaba en un número. Cada vez que renueve el certificado (tienen una duración de 3 meses) se crearán 4 archivos nuevos, con este número incrementado en una unidad, y los 4 enlaces simbólicos apuntarán a estos nuevos archivos.

Tras generar el certificado tengo que configurar el host virtual de Apache. Para ello voy a /etc/apache2/sites-available/ (en este ejemplo supongo que el host virtual ya ha sido habilitado mediante el comando “a2ensite” y que tiene su correspondiente enlace simbólico en /etc/apache2/sites-enabled/)

cd /etc/apache2/sites-available/

y edito el host virtual de mi dominio o dominios:

vi midominio.com.conf

Suponiendo que tengo un <VirtualHost *:80> para atender al puerto 80 (HTTP), duplico esta entrada y en la segunda entrada cambio el 80 por el 443, que es el puerto por defecto de HTTPS.

<VirtualHost *:443>

# Aquí estará el contenido del virtualhost, igual al existente: DocumentRoot, ServerName, elementos de error,...

</VirtualHost>

Además, dentro de este nuevo VirtualHost tengo que indicarle dónde están los certificados. Para ello añado la siguiente información

SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/midominio.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/midominio.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/midominio.com/chain.pem

Con esto ya tendría la configuración realizada. A mayores voy a redireccionar todo el tráfico HTTP hacia el HTTPS. Para ello introduzco la siguiente línea dentro del <VirtualHost *:80>

Redirect permanent / https://midominio.com/

Un ejemplo de host virtual, al que le falta toda la parte específica del lenguaje usado en la aplicación web (FastCgi,…) puede ser el siguiente

<VirtualHost *:80>
      ServerAdmin webmaster@midominio.com
       DocumentRoot /home/midominio/wwww
       ServerName midominio.com
       ServerAlias www.midominio.com
       Redirect permanent / https://midominio.com/
       <Directory />
             Options -Indexes +FollowSymLinks +MultiViews
             AllowOverride All
             Require all granted
       </Directory>
       ErrorLog ${APACHE_LOG_DIR}/midominio-error.log
       LogLevel warn
       CustomLog ${APACHE_LOG_DIR}/midominio-access.log combined
</VirtualHost>
<VirtualHost *:443>
       ServerAdmin webmaster@midominio.com
       DocumentRoot /home/midominio/wwww
       ServerName midominio.com
       ServerAlias www.midominio.com
       <Directory />
             Options -Indexes +FollowSymLinks +MultiViews
             AllowOverride All
             Require all granted
       </Directory>
       SSLEngine on
       SSLCertificateFile /etc/letsencrypt/live/www.midominio.com/cert.pem
       SSLCertificateKeyFile /etc/letsencrypt/live/www.midominio.com/privkey.pem
       SSLCertificateChainFile /etc/letsencrypt/live/www.midominio.com/chain.pem
       ErrorLog ${APACHE_LOG_DIR}/midominio-error.log
       LogLevel warn
       CustomLog ${APACHE_LOG_DIR}/midominio-access.log combined
</VirtualHost>

Ejecuto

apache2ctl -t

para comprobar que la sintaxis de los host virtuales es correcta. Si aparece

Syntax OK

Puedo reinciar Apache y ya tendré listo mi certificado. Para ello ejecuto

service apache2 restart

Y tras recargar mi sitio web en el navegador puedo ver que la comunicación está asegurada

Solo me falta por configurar la renovación automática del certificado, ya que su validez es de 3 meses. Para ello lo que hago es introducir en el cron una tarea que trate de renovar el certificado dos veces por día.

A priori parece que con hacerlo mensualmente llegaría, pero la recomendación de Let’s Encrypt es la siguiente:

Note:

if you’re setting up a cron or systemd job, we recommend running it twice per day (it won’t do anything until your certificates are due for renewal or revoked, but running it regularly would give your site a chance of staying online in case a Let’s Encrypt-initiated revocation happened for some reason). Please select a random minute within the hour for your renewal tasks.

Ejecuto el siguiente comando para ver cómo se realiza el proceso de renovación

certbot renew --post-hook "service apache2 restart"

Su salida es

Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/midominio.com.conf
-------------------------------------------------------------------------------
Cert not yet due for renewal

The following certs are not due for renewal yet:
 /etc/letsencrypt/live/midominio.com/fullchain.pem (skipped)
No renewals were attempted.
No renewals attempted, so not running post-hook

El programa trató de renovar el certificado, pero como no está próximo a caducar no hizo nada (tampoco se reinicia Apache).

Busco la ubicación del programa certbot, ya que en el cron usaré rutas absolutas

which certbot

Su ubicación es

/usr/bin/certbot

Edito el cron

sudo crontab -e

Y añado la siguiente línea, que se ejecuta a las 2:15 y a las 14:15 horas (2 veces al día) y será la encargada de renovar los certificados existentes en la máquina.

15 2,14 * * * /usr/bin/certbot renew --quiet --post-hook "service apache2 restart"

17 comments

  1. Gracias por el comentario. Actualizado el contenido 😉

  2. Gracias por la ayuda, solo una duda:

    Una vez el certificado esta generado para por ejemplo 4 subdominios, pero después mas adelante quiero añadir otro subdominio, tengo que crear el certificado de nuevo con todos los subdominios? o se puede digamos añadir al que ya esta?

    Gracias.

  3. Hola! Un gran tutorial pero tengo un problema de versiones al intentar crear el certificado:

    VersionConflict: (certbot 0.13.0 …..), Requirement.parse(‘certbot==0.10.2’)

    Como podría solucionarlo?

    Gracias!

  4. Vuelves a ejecutar el comando con el nuevo subdominio y automáticamente ya se encarga de generar un nuevo certificado con los subdominios anteriores y con el subdominio nuevo.

  5. Si haces una búsqueda rápida en Google tiene pinta de que es un conflicto entre librerías. Prueba a desisntalar certbot, instalar la versión más actualizada y también a actualizar las librerías de Python.

  6. Jesús muchas gracias por la respuesta.

    He probado a desinstalar certbot y actualizar python y me sigue dando el mismo problema…

  7. Excelente tutorial, al instalar todo tal cual el tutorial me funciono perfecto sin ningun error pero al ingresar al sitio si bien no lo marca NO SEGURO me lo marca como NO COMPLETAMENTE SEGURO que puede ser que no lo ponga como SEGURO

  8. Puedes estar teniendo varios problemas. Los más habituales:
    – Las referencias internas pueden haber quedado con HTTP y no con HTTPS. Lo que tienes es que actualizarlas. En este post explico cómo hacerlo al final (sección “Actualizo http por https en MySQL
    “) https://www.jesusamieiro.com/instalar-un-servidor-web-lemp-iv-certificado-ssltls-de-lets-encrypt/
    – Puede que tengas referencias a recursos externos por HTTP: JS o CSS en un CDN, por poner un ejemplo. Búscalas en el código fuente y, en función de lo que encuentres, actualízalas en el lugar correspondiente.

  9. Me funciono de maravillas con lo que me comentaste, lo que si noto que se puso mucho mas lento el sitio y me deja muchas sesiones de apache abiertas, al desactivar el SSL vuelve el sitio a la normalidad. Uso WordPress

  10. El tutorial funciona de maravillas, no me da error salvo cuando quiero reiniciar el apache y me dice:

    [….] Restarting apache2 (via systemctl): apache2.serviceJob for apache2.service failed because the control process exited with error code.
    See “systemctl status apache2.service” and “journalctl -xe” for details.
    failed!
    Al eliminar las lineas de la ruta donde se encuentran los certificados el apache arranca normalmente

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/
    SSLCertificateKeyFile /etc/letsencrypt/live/
    SSLCertificateChainFile /etc/letsencrypt/live/

  11. En las líneas 2, 3 y 4 te falta el nombre del archivo, solo tienes la ruta hasta el archivo, por eso falla.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.