Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Descripción General
Let’s Encrypt es una autoridad certificadora gratuita y automatizada que provee certificados SSL/TLS confiables por todos los navegadores principales. Certbot es el cliente oficial que automatiza la emisión, instalación y renovación de certificados. Juntos eliminan el costo y trabajo manual de configurar HTTPS.
Antes de Let’s Encrypt, obtener un certificado SSL válido requería comprar a una CA comercial, generar un CSR, validar la propiedad del dominio vía email e instalar el certificado manualmente. El proceso tomaba horas o días y costaba cientos de dólares por año. Let’s Encrypt redujo esto a un solo comando y costo cero.
Cuándo Usar
Usa esta receta cuando:
- Configuras HTTPS para una nueva aplicación web pública.
- Reemplazas certificados expirados o autofirmados con otros confiables por navegadores.
- Automatizas la renovación de certificados para que nunca expiren inadvertidamente.
- Configuras SSL en un reverse proxy (Nginx, Apache, HAProxy) o load balancer.
- Habilitas HTTPS en un contenedor Docker o ingress de Kubernetes.
Implementación Paso a Paso
Instalar Certbot
# Ubuntu / Debian
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
# macOS (para testing)
brew install certbot
# Verificar instalación
certbot --version
Nginx (Plugin Automático)
# Emitir e instalar certificado en un solo paso
certbot --nginx -d example.com -d www.example.com
# Probar renovación automática
sudo certbot renew --dry-run
El plugin --nginx lee automáticamente el server block, instala el certificado y configura la redirección a HTTPS.
# /etc/nginx/sites-available/example.com
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Configuración TLS moderna
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Apache (Plugin Automático)
certbot --apache -d example.com -d www.example.com
# /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# TLS moderno
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder on
</VirtualHost>
Standalone (Sin Servidor Web)
# Usar modo standalone cuando no hay servidor web corriendo
certbot certonly --standalone -d example.com
# Los certificados se guardan en /etc/letsencrypt/live/example.com/
# Configura tu aplicación para leer:
# /etc/letsencrypt/live/example.com/fullchain.pem
# /etc/letsencrypt/live/example.com/privkey.pem
Docker / Certbot
# docker-compose.yml
version: '3'
services:
certbot:
image: certbot/certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
- ./certbot/log:/var/log/letsencrypt
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./certbot/conf:/etc/letsencrypt:ro
- ./certbot/www:/var/www/certbot:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
# nginx.conf
server {
listen 80;
server_name example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://app:3000;
}
}
Auto-Renovación (Systemd Timer)
# Certbot instala un systemd timer automáticamente en la mayoría de sistemas
sudo systemctl status certbot.timer
# Fallback con cron manual
sudo crontab -e
# Agregar:
# 0 3 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"
Lo que funciona
- Usa el plugin del servidor web (
--nginx,--apache) cuando sea posible. Maneja la configuración automáticamente y reduce errores humanos. - Configura la auto-renovación desde el día uno. Los certificados de Let’s Encrypt expiran cada 90 días. Un cron job olvidado causa downtime en producción.
- Incluye dominio y subdominio www en la solicitud del certificado para evitar warnings del navegador en cualquiera de las URLs.
- Redirige HTTP a HTTPS a nivel de servidor web, no en código de aplicación. Es más rápido y confiable.
- Usa
fullchain.pem, nocert.pem. La cadena completa incluye certificados intermedios que los navegadores necesitan para validar la cadena de confianza.
Errores Comunes
- Abrir el puerto 80 solo temporalmente durante la configuración inicial y luego cerrarlo. Let’s Encrypt requiere el puerto 80 abierto para validación HTTP-01 en cada renovación.
- Solicitar un certificado para un dominio interno (ej.,
app.local). Let’s Encrypt solo emite certificados para dominios públicamente resolvibles. - Usar
cert.pemen lugar defullchain.pemcausa errores “certificado no confiado” en algunos navegadores porque faltan intermedios. - No probar la renovación con
--dry-run. Una emisión inicial exitosa no garantiza que la renovación funcionará. Pruébalo antes de los 90 días. - Ejecutar Certbot como root innecesariamente. Usa
sudopara la instalación, pero considera ejecutar la renovación como un usuario dedicado con privilegios limitados.
Tips de Rendimiento
- Habilita OCSP stapling. Los clientes verifican el estado del cert sin contactar a la CA, reduciendo latencia del handshake:
ssl_stapling on;
ssl_stapling_verify on;
- Usa session resumption. Cachéa sesiones TLS para saltar el handshake completo en clientes recurrentes:
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
- Prefiere ECDSA sobre RSA. Llaves más pequeñas significan handshakes más rápidos y menos uso de CPU:
certbot certonly --key-type ecdsa --elliptic-curve secp256r1 -d example.com Related Resources
Playbook de Ansible para Configuración de Servidores
Cómo escribir y ejecutar playbooks de Ansible para provisionar, configurar y gestionar servidores con tareas idempotentes, roles y archivos de inventario.
RecipeFundamentos de Docker
Cómo containerizar una aplicación, escribir un Dockerfile y ejecutar contenedores con Docker Compose.
RecipeGestionar Secretos de Aplicaciones de Forma Segura
Cómo almacenar, rotar e inyectar API keys, contraseñas de base de datos y certificados sin hardcodearlos en código fuente o archivos de entorno.
Preguntas frecuentes
- ¿Cuál es la diferencia entre un certificado autofirmado y uno firmado por CA?
- Un certificado autofirmado lo emites tú y generará advertencias en el navegador. Un certificado firmado por CA es confiable por defecto porque los navegadores confían en la Autoridad Certificadora...
- ¿Cómo funciona Let's Encrypt?
- Let's Encrypt es una CA gratuita que valida la propiedad del dominio mediante desafíos HTTP o DNS y emite certificados de corta duración, típicamente válidos por 90 días.
- ¿Por qué debería automatizar la renovación de certificados?
- Los certificados TLS expiran. La renovación automatizada previene interrupciones del servicio por certificados vencidos y reduce el trabajo operativo manual.