Skip to main content

HTTP-01 Challenge

Cuando solicitas un certificado, Let's Encrypt necesita verificar que controlas el dominio o subdominio específico para el que estás solicitando. El HTTP-01 Challenge verifica esto haciendo una solicitud HTTP en el puerto 80.

Por ejemplo: si solicitas certificado para api.domain.com, Let's Encrypt valida solo ese subdominio, no el dominio completo. Para cubrir múltiples subdominios, necesitas solicitar certificado para cada uno o usar wildcard vía DNS-01 Challenge que veremos más adelante.

Prerrequisito de DNS: Solo el registro A/CNAME apuntando a la IP del servidor (ya existente si el sitio funciona). No es necesario crear ningún registro adicional.

Prerrequisito del servidor:

  • Puerto 80 accesible públicamente
  • Servidor web respondiendo solicitudes HTTP

Cómo funciona:

  1. Ejecutas Certbot solicitando un certificado
  2. Let's Encrypt genera un token único y lo envía a Certbot
  3. Certbot crea automáticamente el archivo en /.well-known/acme-challenge/TOKEN
  4. Let's Encrypt hace solicitud HTTP para verificar el token
  5. Si se valida, el certificado es emitido
  6. Certbot elimina automáticamente el archivo de token

Certbot es el cliente ACME oficial desarrollado por Electronic Frontier Foundation (EFF) en asociación con Let's Encrypt. Automatiza todo el proceso de obtención y renovación de certificados.

¿Necesitas crear cuenta? ¡No! Certbot crea una cuenta automáticamente en la primera ejecución. Solo solicita un email (opcional) para avisos de expiración. Las credenciales quedan en /etc/letsencrypt/accounts/.

Como ACME es un protocolo abierto, existen otros clientes compatibles: acme.sh (shell script), Caddy (servidor web), Traefik (proxy reverso), cert-manager (Kubernetes).

Certbot es herramienta, no servicio. Lo instalas una única vez y él gestiona múltiples certificados para diferentes dominios en el mismo servidor. Después de la primera ejecución, Certbot configura automáticamente un systemd timer (o cron job) que verifica renovaciones 2x al día. Si un certificado está próximo al vencimiento, renueva automáticamente.

Importante: No necesitas crear ningún archivo manualmente. Certbot se encarga de todo el proceso.

Certbot es una aplicación completamente separada de tu aplicación real. Arquitectura:

Instalación de Certbot

# Ubuntu/Debian
sudo apt update
sudo apt install certbot

# Plugin para Nginx si es necesario
sudo apt install python3-certbot-nginx

# Plugin para Apache si es necesario
sudo apt install python3-certbot-apache

# CentOS/RHEL/Rocky + plugin
sudo dnf install certbot python3-certbot-nginx

Los plugins no son obligatorios, pero si quieres usar los comandos --nginx o --apache, que veremos adelante, facilitará mucho ya que configuran esos servidores web automáticamente. Sin plugin, usa certonly y configura manualmente.

ModoPluginQué hace
--nginxRequiere pluginObtiene certificado y configura Nginx
--apacheRequiere pluginObtiene certificado y configura Apache
certonlyNo requiereSolo obtiene certificado (configuración manual)

Obtener certificado

# Con Nginx (recomendado - configura automáticamente)
sudo certbot --nginx -d subdomain.domain.com.br

# Con Apache
sudo certbot --apache -d subdomain.domain.com.br

# Solo certificado (sin configurar servidor)
sudo certbot certonly --webroot -w /var/www/html -d subdomain.domain.com.br

Certbot hace automáticamente: recibe el token, crea el archivo en /.well-known/acme-challenge/, aguarda validación, elimina el archivo e instala el certificado creando el timer para renovación en el sistema.

Comandos Útiles

# Verificar el timer de renovación automática
systemctl list-timers | grep certbot

# Listar todos los certificados gestionados
certbot certificates

# Renovar todos los certificados (ejecutado automáticamente por el timer)
certbot renew

Dónde Quedan los Certificados

Después de validación exitosa, Certbot almacena los certificados en /etc/letsencrypt/:

/etc/letsencrypt/
├── live/
│ └── domain.com/
│ ├── cert.pem # Certificado del servidor
│ ├── chain.pem # Cadena intermedia
│ ├── fullchain.pem # cert.pem + chain.pem (usa este en el servidor)
│ └── privkey.pem # Clave privada (¡proteger!)
├── archive/ # Historial de certificados anteriores
├── renewal/ # Configuraciones de renovación
└── accounts/ # Credenciales de la cuenta ACME

En la configuración del servidor, usa:

  • ssl_certificate: apunta a fullchain.pem
  • ssl_certificate_key: apunta a privkey.pem
# Verificar certificados instalados
sudo certbot certificates

# Salida esperada:
# Certificate Name: domain.com
# Domains: domain.com
# Expiry Date: 2024-04-15 (VALID: 89 days)
# Certificate Path: /etc/letsencrypt/live/domain.com/fullchain.pem
# Private Key Path: /etc/letsencrypt/live/domain.com/privkey.pem

Renovación Manual (sistemas antiguos)

En sistemas sin systemd timer, agrega un cron job:

# Editar crontab
sudo crontab -e

# Agregar línea para renovación 2x al día
0 0,12 * * * certbot renew --quiet --post-hook "systemctl reload nginx"

Flujo de renovación:

  1. Timer/cron ejecuta certbot renew
  2. Certbot verifica certificados instalados
  3. Identifica certificados con menos de 30 días de validez
  4. Inicia proceso de renovación (repite validación HTTP-01)
  5. Sustituye certificado antiguo por el nuevo
  6. Ejecuta post-hook para recargar servidor web

Riesgos y Consideraciones de Seguridad

1. Rate Limits

Como Let's Encrypt es gratuito, existen límites para evitar abuso:

LímiteSignificadoEjemplo
50 certificados/dominio/semanaMáximo de 50 certificados para subdominios de tu dominioapi.site.com, www.site.com, etc. sumados
5 duplicados/semanaMismo certificado (exactos dominios) solo puede ser emitido 5xEvita loops accidentales en scripts
10 cuentas/IP/3hCreación de nuevas cuentas ACME limitadaAfecta solo primera instalación

En la práctica: Estos límites raramente afectan uso normal. Problemas surgen en:

  • Scripts con bugs que piden certificados en loop
  • Ambientes de test/desarrollo sin usar staging

Solución: Usa --test-cert (staging) para pruebas - tiene límites mucho mayores:

# Ambiente de pruebas (no genera certificado válido, pero prueba todo el proceso)
certbot certonly --test-cert --nginx -d test.domain.com

# Producción (certificado real)
certbot certonly --nginx -d prod.domain.com

2. ¿Y si la Renovación Falla?

Si el timer automático falla en renovar, el certificado expira y tu sitio queda sin HTTPS. Esto puede ocurrir por:

Causa comúnQué pasó
Puerto 80 bloqueadoFirewall cambió, Let's Encrypt no puede validar
Servidor paradoNginx/Apache no estaba corriendo en el momento de la renovación
Dominio cambióDNS no apunta más al servidor
Disco llenoNo puede guardar nuevo certificado

Cómo verificar si está todo ok:

# Ver estado de los certificados y cuándo expiran
sudo certbot certificates

# Probar si la renovación va a funcionar (sin renovar de verdad)
sudo certbot renew --dry-run

Monitoreo simple: Agrega una alerta por email si la renovación falla:

# Agregar en crontab (sudo crontab -e)
0 8 * * * certbot renew --dry-run --quiet || echo "ALERTA: Renovación SSL falló!" | mail -s "Certbot Falló" [email protected]

Esto corre todos los días a las 8h y solo envía email si hay problema.

3. Protegiendo tu Dominio con CAA Records

Cualquier persona puede intentar obtener un certificado para tu dominio. Si un atacante consigue acceso temporal a tu servidor o DNS, podría obtener un certificado válido.

Para solucionar esta situación tenemos el CAA (Certificate Authority Authorization) que es un registro DNS que dice "solo ESTA autoridad certificadora puede emitir certificados para mi dominio".

# Agrega estos registros DNS en tu proveedor (Cloudflare, Route53, etc.)

# Solo Let's Encrypt puede emitir certificados para este dominio
domain.com. CAA 0 issue "letsencrypt.org"

# Bloquea emisión de wildcards (opcional)
domain.com. CAA 0 issuewild ";"

# Recibir email si alguien intenta emitir certificado no autorizado
domain.com. CAA 0 iodef "mailto:[email protected]"

Verificar si CAA está configurado:

dig CAA domain.com

4. Protegiendo la Clave Privada

La clave privada (privkey.pem) es el secreto más importante. Quien tenga acceso puede hacerse pasar por tu sitio.

# Verificar permisos (debe ser 600, solo root lee)
ls -la /etc/letsencrypt/live/domain.com/

# Corregir si es necesario
sudo chmod 600 /etc/letsencrypt/live/domain.com/privkey.pem
sudo chown root:root /etc/letsencrypt/live/domain.com/privkey.pem

Nunca hagas:

  • Copiar claves a repositorios git
  • Enviar claves por email/chat
  • Dar permiso de lectura a otros usuarios