
30 Jul Cómo Resolver Errores de Renovación SSL con Certbot: El Problema de los Certificados Huérfanos
Como ingeniero de infraestructura, uno de los problemas más frustrantes que puedes encontrar es cuando tu script de renovación automática de certificados SSL falla inesperadamente. Hoy te voy a contar sobre un error común que me encontré recientemente y cómo resolverlo de manera definitiva.
El Problema: Timeout Durante la Renovación
Todo comenzó con este error en mi script de renovación que deje en el post de este mismo blog (“Como instalar y configurar Certbot para NGINX en Amazon Linux 2023“) :
Certbot failed to authenticate some domains (authenticator: nginx). The Certificate Authority reported these problems: Domain: dev.domain.com Type: connection Detail: Fetching http://dev.domain.com/.well-known/acme-challenge/: Timeout during connect (likely firewall problem)
Al principio pensé en las causas típicas:
- Problemas de firewall
- Security Groups mal configurados en AWS
- DNS mal configurado
- Nginx caído
Pero después de verificar todo esto, el problema persistía. ¿La causa real? Certificados huérfanos.
¿Qué son los Certificados Huérfanos?
Un certificado huérfano es un certificado SSL que existe en el sistema de Let’s Encrypt pero ya no tiene una configuración correspondiente en tu servidor web. Esto suele ocurrir cuando:
- Eliminas un dominio de tu configuración de nginx
- Migras servicios a otros servidores
- Cambias la arquitectura de tu aplicación
- Removes subdominios que ya no usas
En mi caso, tenía un certificado para dev.wms-alphas.com
que ya no existía en mi configuración de nginx, pero certbot seguía intentando renovarlo automáticamente.
Diagnóstico Paso a Paso
1. Verificar Certificados Existentes
# Listar todos los certificados sudo certbot certificates # Ver detalles específicos sudo certbot certificates --cert-name dev.domain.com
2. Verificar Configuración de Nginx
# Listar sitios habilitados ls -la /etc/nginx/sites-enabled/ # Buscar configuraciones de dominio grep -r "server_name" /etc/nginx/sites-enabled/ # Verificar dominio específico grep -r "dev.domain.com" /etc/nginx/sites-enabled/
3. Identificar el Desajuste
Si el comando certbot certificates
muestra un certificado pero grep
no encuentra configuración en nginx, tienes un certificado huérfano.
La Solución: Limpieza de Certificados
Opción 1: Eliminar Certificados No Utilizados (Recomendado)
# Eliminar el certificado huérfano sudo certbot delete --cert-name dev.domain.com # Verificar que se eliminó correctamente sudo certbot certificates # Probar renovación sudo certbot renew --dry-run
Opción 2: Crear Configuración Temporal
Si planeas usar el dominio en el futuro:
# /etc/nginx/sites-available/dev.domain.com server { listen 80; server_name dev.domain.com; location /.well-known/acme-challenge/ { root /var/www/html; allow all; } location / { return 503; # Service unavailable } }
Script de Renovación Mejorado
Aquí tienes un script optimizado que evita estos problemas en el futuro:
#!/bin/bash # updatessl.sh - Versión mejorada con validaciones echo "=== SSL Certificate Renewal Script ===" # Verificar configuración de nginx if ! sudo nginx -t; then echo "❌ ERROR: Invalid nginx configuration" exit 1 fi # Verificar certificados vs configuración echo "🔍 Checking for orphaned certificates..." for cert_conf in /etc/letsencrypt/renewal/*.conf; do if [ -f "$cert_conf" ]; then cert_name=$(basename "$cert_conf" .conf) domains=$(grep "^domains = " "$cert_conf" | cut -d' ' -f3- | tr ',' ' ') for domain in $domains; do if ! grep -r "$domain" /etc/nginx/sites-enabled/ > /dev/null; then echo "⚠️ WARNING: Domain $domain has no nginx configuration" echo " Consider running: sudo certbot delete --cert-name $cert_name" fi done fi done # Proceder con renovación echo "🔄 Starting certificate renewal..." sudo systemctl stop nginx if sudo certbot renew --force-renewal; then echo "✅ Certificate renewal successful" else echo "❌ Certificate renewal failed" sudo systemctl start nginx exit 1 fi # Reiniciar nginx if sudo systemctl start nginx; then echo "✅ Nginx restarted successfully" sudo systemctl status nginx --no-pager -l else echo "❌ Failed to start nginx" sudo journalctl -xeu nginx.service --no-pager exit 1 fi echo "🎉 SSL renewal completed successfully!"
Automatización con AWS
Para entornos de producción, considera automatizar esto con Infrastructure as Code:
# Lambda function para renovación automática import boto3 import json def lambda_handler(event, context): ssm = boto3.client('ssm') commands = [ "sudo certbot certificates", "sudo certbot renew --quiet --no-self-upgrade", "sudo systemctl reload nginx" ] response = ssm.send_command( InstanceIds=[event['instance_id']], DocumentName='AWS-RunShellScript', Parameters={'commands': commands}, TimeoutSeconds=300 ) return { 'statusCode': 200, 'body': json.dumps({ 'message': 'SSL renewal initiated', 'command_id': response['Command']['CommandId'] }) }
Mejores Prácticas
- Auditoría Regular: Revisa periódicamente tus certificados vs configuración de nginx
- Monitoreo: Implementa alertas para fallos de renovación
- Documentación: Mantén un registro de qué dominios están activos
- Automatización: Usa Infrastructure as Code para gestionar certificados
- Testing: Siempre usa
--dry-run
antes de renovaciones forzadas
Conclusión
Los certificados huérfanos son un problema común pero fácil de resolver una vez que sabes qué buscar. La clave está en mantener sincronizada tu configuración de certificados con tu configuración de servidor web.
Este tipo de problemas son perfectos ejemplos de por qué la infraestructura debe tratarse como código: versionada, documentada y auditable.
Enlaces Útiles
Happy Hacking!