ACME (Automatic Certificate Management Environment, RFC 8555) es el protocolo que permite a un programa pedir, validar, renovar y revocar certificados TLS sin intervención humana. Lo usan Let's Encrypt, ZeroSSL, Google Trust Services y otras CA, y está integrado en herramientas como Certbot, Caddy o Traefik. En esta guía verás cómo funciona el protocolo, qué desafío elegir en cada caso y cómo montar en Ubuntu 24.04 una emisión y renovación automática con Certbot que puedas verificar.
Requisitos previos
Para la parte práctica necesitas:
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, y un usuario no root con privilegios
sudo. - Un dominio con un registro DNS
A(yAAAAsi usas IPv6) que apunte ayour_server_ip. - Nginx instalado (
sudo apt install nginx) y el puerto 80 accesible desde Internet, además del 443.
Sustituye your_domain por tu dominio en todos los comandos.
Cómo funciona ACME
Una emisión ACME sigue siempre los mismos pasos entre el cliente (Certbot, acme.sh...) y el servidor de la CA:
- Directorio. El cliente descarga un documento JSON con las URL de cada operación.
- Cuenta. El cliente genera un par de claves de cuenta y se registra. Todas las peticiones posteriores van firmadas con esa clave.
- Pedido (order). El cliente pide un certificado para una lista de nombres.
- Autorizaciones y desafíos. Por cada nombre, la CA propone uno o varios desafíos para demostrar el control del dominio.
- Validación. El cliente publica la respuesta y avisa a la CA, que la comprueba desde varios puntos de Internet.
- Finalización. Con todos los nombres validados, el cliente envía una CSR y descarga el certificado con su cadena.
Puedes ver el directorio de Let's Encrypt tú mismo:
curl -s https://acme-v02.api.letsencrypt.org/directory
{
"keyChange": "https://acme-v02.api.letsencrypt.org/acme/key-change",
"meta": { ... },
"newAccount": "https://acme-v02.api.letsencrypt.org/acme/new-acct",
"newNonce": "https://acme-v02.api.letsencrypt.org/acme/new-nonce",
"newOrder": "https://acme-v02.api.letsencrypt.org/acme/new-order",
"renewalInfo": "https://acme-v02.api.letsencrypt.org/acme/renewal-info",
"revokeCert": "https://acme-v02.api.letsencrypt.org/acme/revoke-cert"
}
Let's Encrypt ofrece además un entorno de pruebas (staging) en https://acme-staging-v02.api.letsencrypt.org/directory. Emite certificados que no son de confianza pero tiene límites mucho más altos, así que es donde debes probar cualquier configuración nueva.
Tipos de desafío
La elección del desafío determina qué necesita el servidor y qué tipo de certificado puedes obtener:
| Desafío | Cómo se valida | Requisitos | Comodines | Uso típico |
|---|---|---|---|---|
| HTTP-01 | La CA descarga http://your_domain/.well-known/acme-challenge/<token> | Puerto 80 accesible desde Internet | No | Servidores web públicos |
| DNS-01 | La CA consulta el registro TXT _acme-challenge.your_domain | API del proveedor DNS | Sí | Comodines, servidores internos, varios servidores |
| TLS-ALPN-01 | La CA conecta al puerto 443 con el protocolo ALPN acme-tls/1 | Puerto 443 y un cliente que lo soporte | No | Proxies como Caddy o Traefik sin puerto 80 |
Algunas consecuencias prácticas:
- HTTP-01 sigue las redirecciones, así que puedes redirigir todo a HTTPS siempre que
/.well-known/acme-challenge/responda. - Con DNS-01 el servidor no tiene que ser accesible desde Internet, lo que lo hace útil para servicios internos con nombre público.
- Si hay varios servidores detrás de un balanceador, HTTP-01 exige que cualquiera de ellos pueda servir el token; DNS-01 evita el problema.
Comparativa de clientes ACME
| Cliente | Lenguaje | Puntos fuertes | A tener en cuenta |
|---|---|---|---|
| Certbot | Python | Cliente de referencia de la EFF, plugins para Nginx, Apache y muchos DNS, temporizador incluido | Instalación recomendada con snap |
| acme.sh | Shell | Sin dependencias, más de 150 APIs DNS, instalación por usuario | Su CA por defecto es ZeroSSL; usa --server letsencrypt si prefieres Let's Encrypt |
| lego | Go | Binario único, muchos proveedores DNS, fácil de usar en contenedores | La renovación la programas tú (cron o temporizador) |
| Caddy / Traefik | Go | ACME integrado en el servidor web o proxy, sin configuración aparte | Los certificados los gestiona el propio proceso |
Si ya usas Nginx o Apache en un servidor, Certbot es la opción más directa y la que usa el resto de esta guía.
Paso 1: Instalar Certbot
Instala Certbot con snap, que es el método que mantiene el proyecto, y crea un enlace para poder ejecutarlo como certbot:
sudo apt remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
certbot --version
El último comando debe mostrar una línea certbot X.Y.Z con la versión instalada.
Paso 2: Preparar el desafío HTTP-01 con webroot
El método webroot hace que Certbot escriba el token en un directorio que Nginx ya sirve, sin detener el servidor ni tocar su configuración. Crea un directorio dedicado:
sudo mkdir -p /var/www/acme
Edita el bloque server del puerto 80 de tu sitio:
sudo nano /etc/nginx/sites-available/your_domain
Sirve los tokens desde ese directorio y redirige todo lo demás a HTTPS:
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
location /.well-known/acme-challenge/ {
root /var/www/acme;
}
location / {
return 301 https://$host$request_uri;
}
}
Activa el sitio si aún no lo está, recarga y comprueba que Nginx sirve un archivo de prueba en esa ruta:
sudo ln -sf /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo mkdir -p /var/www/acme/.well-known/acme-challenge
echo ok | sudo tee /var/www/acme/.well-known/acme-challenge/test
curl http://your_domain/.well-known/acme-challenge/test
ok
Borra el archivo de prueba:
sudo rm /var/www/acme/.well-known/acme-challenge/test
Paso 3: Probar contra staging y emitir el certificado
Simula la emisión contra el entorno de staging con --dry-run. Si algo falla, no consumirás los límites de producción:
sudo certbot certonly --webroot -w /var/www/acme -d your_domain -d www.your_domain --dry-run
The dry run was successful.
Emite ahora el certificado real. La primera ejecución crea la cuenta ACME y te pide un correo de contacto:
sudo certbot certonly --webroot -w /var/www/acme -d your_domain -d www.your_domain
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem
Key is saved at: /etc/letsencrypt/live/your_domain/privkey.pem
Certbot guarda la clave de la cuenta en /etc/letsencrypt/accounts/ y los parámetros de esta emisión (método, directorio webroot, nombres) en /etc/letsencrypt/renewal/your_domain.conf. Las renovaciones reutilizan ese archivo.
Añade el bloque HTTPS a Nginx apuntando a fullchain.pem y privkey.pem:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name your_domain www.your_domain;
ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
root /var/www/html;
}
sudo nginx -t && sudo systemctl reload nginx
Paso 4: Automatizar la renovación
Los certificados de Let's Encrypt duran 90 días y la tendencia del sector es reducir aún más su vida útil, así que la renovación debe ser totalmente automática. El snap de Certbot instala un temporizador de systemd que ejecuta certbot renew dos veces al día:
systemctl list-timers snap.certbot.renew.timer
certbot renew solo actúa sobre los certificados que están a menos de 30 días de caducar, por lo que ejecutarlo a menudo es seguro. Falta un detalle: Nginx no carga el certificado nuevo hasta que se recarga. Crea un hook de despliegue, que Certbot ejecuta únicamente tras una renovación correcta:
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/usr/bin/env bash
set -euo pipefail
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Simula una renovación completa, hooks incluidos:
sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/your_domain/fullchain.pem (success)
Let's Encrypt ya no envía correos de aviso de caducidad, así que conviene vigilar la fecha por tu cuenta, por ejemplo desde tu sistema de monitorización. Para consultarla a mano:
sudo certbot certificates
Límites de emisión
Let's Encrypt aplica límites para proteger su infraestructura. Los que más afectan en la práctica son:
- Un número máximo de certificados nuevos por dominio registrado cada semana (50 en el momento de escribir esta guía).
- Un máximo de 5 certificados por semana con exactamente el mismo conjunto de nombres.
- Un límite de validaciones fallidas por nombre y cuenta cada hora.
Las renovaciones de un certificado existente tienen un trato más permisivo, pero repetir emisiones de prueba en producción es la forma más habitual de bloquearse. Usa siempre --dry-run para probar y evita --force-renewal salvo que realmente necesites reemitir. Los valores actuales están en la documentación de límites de Let's Encrypt.
Solución de problemas
Invalid response from http://your_domain/.well-known/acme-challenge/...: 404. Nginx no sirve el directorio webroot para ese nombre. Revisa que el server_name del bloque del puerto 80 incluye todos los nombres pedidos y repite la prueba del paso 2.
Timeout during connect (likely firewall problem). La CA no llega al puerto 80. Comprueba el cortafuegos (sudo ufw status, y sudo ufw allow 'Nginx Full' si hace falta) y que el registro AAAA, si existe, apunta a una IPv6 que el servidor atiende: Let's Encrypt prefiere IPv6 cuando hay registro AAAA.
DNS problem: NXDOMAIN looking up A for your_domain. El registro DNS no existe o aún no se ha propagado. Compruébalo con dig +short A your_domain.
Para ver el detalle de cualquier error, consulta el registro de Certbot:
sudo tail -n 50 /var/log/letsencrypt/letsencrypt.log
Conclusión
Has visto las fases del protocolo ACME, cuándo usar HTTP-01, DNS-01 o TLS-ALPN-01, y has montado con Certbot una emisión por webroot con renovación automática y recarga de Nginx verificada con --dry-run. Como siguientes pasos, puedes pasar a DNS-01 para obtener certificados comodín, añadir una alerta de caducidad en tu monitorización o probar un servidor con ACME integrado como Caddy para servicios nuevos.