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 (y AAAA si usas IPv6) que apunte a your_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:

  1. Directorio. El cliente descarga un documento JSON con las URL de cada operación.
  2. Cuenta. El cliente genera un par de claves de cuenta y se registra. Todas las peticiones posteriores van firmadas con esa clave.
  3. Pedido (order). El cliente pide un certificado para una lista de nombres.
  4. Autorizaciones y desafíos. Por cada nombre, la CA propone uno o varios desafíos para demostrar el control del dominio.
  5. Validación. El cliente publica la respuesta y avisa a la CA, que la comprueba desde varios puntos de Internet.
  6. 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íoCómo se validaRequisitosComodinesUso típico
HTTP-01La CA descarga http://your_domain/.well-known/acme-challenge/<token>Puerto 80 accesible desde InternetNoServidores web públicos
DNS-01La CA consulta el registro TXT _acme-challenge.your_domainAPI del proveedor DNSSíComodines, servidores internos, varios servidores
TLS-ALPN-01La CA conecta al puerto 443 con el protocolo ALPN acme-tls/1Puerto 443 y un cliente que lo soporteNoProxies 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

ClienteLenguajePuntos fuertesA tener en cuenta
CertbotPythonCliente de referencia de la EFF, plugins para Nginx, Apache y muchos DNS, temporizador incluidoInstalación recomendada con snap
acme.shShellSin dependencias, más de 150 APIs DNS, instalación por usuarioSu CA por defecto es ZeroSSL; usa --server letsencrypt si prefieres Let's Encrypt
legoGoBinario único, muchos proveedores DNS, fácil de usar en contenedoresLa renovación la programas tú (cron o temporizador)
Caddy / TraefikGoACME integrado en el servidor web o proxy, sin configuración aparteLos 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.