DEV Community

Cover image for Certificación de dominio con Let’s Encrypt, NGINX y Docker Compose
Euda
Euda

Posted on

14 4

Certificación de dominio con Let’s Encrypt, NGINX y Docker Compose

Algunas definiciones

¿Qué es un Certificado SSL?

Un certificado SSL es un tipo de certificado digital que proporciona autenticación para un sitio web y habilita una conexión encriptada. Estos certificados comunican al cliente que el host del servicio web demostró la propiedad del dominio a la autoridad de certificación en el momento de la emisión del certificado.

SSL (Secure Socket Layer) es un protocolo de seguridad que encripta el envío y recepción de información entre el servidor y el cliente. Este crea una capa de conexión segura entre el navegador y el servidor del sitio web al que el usuario se conecta. Cualquier información que pase a través de esta capa está encriptada y es descifrada cuando llega a su destino.

Alt Text

Let’s Encrypt

Let's Encrypt es una autoridad de certificación (también conocidas como AC o CA por sus siglas en inglés) gratuita, automatizada, y abierta, que existe para el beneficio del público. Es un servicio provisto por el Internet Security Research Group o ISRG.

Certbot

Cerbot es un cliente extensible con todas las funciones para Let’s Encrypt CA, o cualquier otra autoridad de certificación que se comunique a través del protocolo ACME, capaz de automatizar las tareas de obtener certificados y configurar servidores web para usarlos.

Nginx

NGINX es un servidor web/proxy inverso ligero de alto rendimiento y un proxy para protocolos de correo electrónico.​​

Cómo certificar

Pre-Requisitos

Compose es una herramienta para definir y ejecutar aplicaciones Docker de varios contenedores. Se usa un archivo YAML para configurar los servicios de tu aplicación y luego, con un solo comando, crea e inicia todos los servicios desde tu configuración.

Pasos

1. Lo primero que haremos es crear los directorios donde Certbot alojará la configuración de los certificados y donde pondremos la configuración de nuestro servidor Nginx:

data/certbot/www/.well-known
Enter fullscreen mode Exit fullscreen mode

Es muy importante que esté creado el directorio .well-known ya que en el mismo se guardará el challenge que Let’s encrypt utiliza para corroborar que tenemos control sobre el dominio. Es útil conocer los diferentes tipos de challenges que existen para elegir el más adecuado según el caso, es decir, el tipo de validación que Let’s Encrypt utiliza para verificar el control sobre el dominio.

2. Luego, crearemos el archivo de configuración de Nginx dentro del directorio recién creado, con el siguiente contenido:

server {
  listen 80;
  server_name NOMBRE_DEL_HOST;
  location / {
    return 301 https:// NOMBRE_DEL_HOST;
  }
  location /.well-known/acme-challenge/ {
    root /var/www/certbot;
  }
}
server {
  listen 443 ssl;
  server_name NOMBRE_DEL_HOST;
  location / {
    proxy_pass http://NOMBRE_DEL_HOST;
  }
  ssl_certificate /etc/letsencrypt/live/NOMBRE_DEL_HOST/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/NOMBRE_DEL_HOST/privkey.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
Enter fullscreen mode Exit fullscreen mode

El archivo de configuración deberá estar en dicho directorio:
data/nginx/web.conf

3. Una vez listo, pasaremos a crear el Compose que vamos a utilizar:

version: "3"
services:
  nginx:
     image: nginx:1.15-alpine
     ports:
       - "80:80"
       - "443:443"
     volumes:
       - ./data/nginx:/etc/nginx/conf.d
       - ./data/certbot/conf:/etc/letsencrypt
       - ./data/certbot/www:/var/www/certbot
     command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

  certbot:
     image: certbot/certbot
     volumes:
       - ./data/certbot/conf:/etc/letsencrypt
       - ./data/certbot/www:/var/www/certbot
     entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
Enter fullscreen mode Exit fullscreen mode

Creado el Compose, no lo ejecutaremos, porque fallará la creación del Nginx debido a que no se encuentra creado el certificado que declaramos anteriormente en el archivo de configuración de Nginx.


Vamos a explicar un poco lo que hicimos en ese Compose: cruzamos datos entre Certbot y Nginx mediante los directorios creados anteriormente. Esto se debe a que necesitamos que el contenedor Nginx pueda acceder a los certificados y el challenge creados por el contenedor de Certbot.

En el contenedor de Certbot agregamos un entrypoint el cual verifica cada 12 horas si se puede renovar el certificado.

Por su parte, en el contenedor de Nginx agregamos un command el cual permite iniciar Nginx en primer plano y recarga su configuración y certificados cada 6 horas en segundo plano, asegurando que siempre tenga los nuevos certificados que se generen.


4. Finalmente, debemos crear el siguiente script cambiando los valores de domains y email:

#!/bin/bash
if ! [ -x "$(command -v docker-compose)" ]; then
echo 'Error: docker-compose is not installed.' >&2
exit 1
fi
domains=(example.org www.example.org)
rsa_key_size=4096
data_path="./data/certbot"
email="" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
if [ -d "$data_path" ]; then
read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
exit
fi
fi
if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
echo "### Downloading recommended TLS parameters ..."
mkdir -p "$data_path/conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
echo
fi
echo "### Creating dummy certificate for $domains ..."
path="/etc/letsencrypt/live/$domains"
mkdir -p "$data_path/conf/live/$domains"
docker-compose run --rm --entrypoint "\
openssl req -x509 -nodes -newkey rsa:1024 -days 1\
-keyout '$path/privkey.pem' \
-out '$path/fullchain.pem' \
-subj '/CN=localhost'" certbot
echo
echo "### Starting nginx ..."
docker-compose up --force-recreate -d nginx
echo
echo "### Deleting dummy certificate for $domains ..."
docker-compose run --rm --entrypoint "\
rm -Rf /etc/letsencrypt/live/$domains && \
rm -Rf /etc/letsencrypt/archive/$domains && \
rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
echo
echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
domain_args=""
for domain in "${domains[@]}"; do
domain_args="$domain_args -d $domain"
done
# Select appropriate email arg
case "$email" in
"") email_arg="--register-unsafely-without-email" ;;
*) email_arg="--email $email" ;;
esac
# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi
docker-compose run --rm --entrypoint "\
certbot certonly --webroot -w /var/www/certbot \
$staging_arg \
$email_arg \
$domain_args \
--rsa-key-size $rsa_key_size \
--agree-tos \
--force-renewal" certbot
echo
echo "### Reloading nginx ..."
docker-compose exec nginx nginx -s reload
echo "### Docker Compose up"
docker-compose up -d

El script debe estar en el mismo directorio donde se encuentra el docker-compose y el directorio data que creamos anteriormente. Vamos a darle permiso de ejecución al script y luego ejecutarlo:

chmod +x init-letsencrypt.sh 
sudo ./init-letsencrypt.sh
Enter fullscreen mode Exit fullscreen mode

Como dijimos anteriormente, si queremos utilizar el comando docker-compose upno funcionará porque no se encuentran creados los certificados que seteamos en la configuración de Nginx. Ahí es donde entra en juego el script. Este script lo que hace es crear certificados dummies utilizando el contenedor de Certbot, para poder inicializar el contenedor de Nginx sin errores. Luego de que el contenedor esté inicializado, elimina los certificados dummies, le pide a Let’sEncrypt certificados para nuestro dominio y reinicia la configuración del contenedor de Nginx para recargar los certificados válidos. De este modo, no va a ser necesario utilizar dicho comando.

Si al ejecutar el script falla la creación de los certificados, es muy importante que lean y resuelvan el inconveniente antes de volver a ejecutarlo, ya que Let’sEncrypt bloqueará el dominio si hacen más de 5 intentos fallidos.


Por último, cabe aclarar que en este artículo tomamos información de varias fuentes, recopilando aquellas más completas para que este paso a paso resulte más fácil y práctico. Espero que les sea útil y cualquier consulta no duden en dejarla en los comentarios.

Para más info sobre este tema recomendamos nuestra nota en Medium:

¡Muchos éxitos!

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Billboard image

Try REST API Generation for Snowflake

DevOps for Private APIs. Automate the building, securing, and documenting of internal/private REST APIs with built-in enterprise security on bare-metal, VMs, or containers.

  • Auto-generated live APIs mapped from Snowflake database schema
  • Interactive Swagger API documentation
  • Scripting engine to customize your API
  • Built-in role-based access control

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay