Loading...

Seguridad · 11 min de lectura

Certbot: obtén y renueva certificados Let's Encrypt de la forma correcta

Certbot es el cliente ACME gratuito de la EFF: pide certificados a Let's Encrypt, demuestra que controlas el dominio, instala el certificado en nginx o Apache y lo renueva automáticamente. Instálalo con snap, emite con certbot --nginx o --apache, usa DNS-01 para los wildcard, y confirma la renovación con certbot renew --dry-run.

Actualizado

Certbot: obtén y renueva certificados Let's Encrypt de la forma correcta

Qué es certbot, y qué hace en realidad

Certbot es un cliente ACME gratuito y de código abierto mantenido por la Electronic Frontier Foundation. ACME es el protocolo que usa Let's Encrypt (y un número creciente de otras CA) para emitir certificados sin un humano en el proceso. Certbot lo habla por ti: crea una clave de cuenta, pide un certificado a la CA, demuestra que controlas el dominio, guarda el certificado y la clave en disco, y, si lo dejas, edita la configuración de tu servidor web y renueva todo antes de que caduque.

La prueba de control es un challenge, y certbot admite dos. HTTP-01: la CA pide un token aleatorio en http://example.com/.well-known/acme-challenge/<token> en el puerto 80, y certbot se asegura de que ese archivo se sirva. DNS-01: la CA busca un registro TXT en _acme-challenge.example.com, y certbot (o tú) lo publica. HTTP-01 es la opción fácil por defecto; DNS-01 es la única forma de obtener un wildcard y la manera de emitir para un servidor que no es accesible desde internet.

Quién hace qué lo fijan dos tipos de plugins. Un authenticator responde al challenge (--nginx, --apache, --webroot, --standalone, --manual, o un plugin de DNS como --dns-cloudflare). Un installer coloca el certificado en una configuración de servidor (nginx o apache). certbot --nginx hace ambas cosas; certbot certonly ... solo obtiene el certificado y deja la configuración en tus manos.

Todo queda bajo /etc/letsencrypt. Los archivos a los que apunta un servidor viven en /etc/letsencrypt/live/<cert-name>/: fullchain.pem (tu certificado más el intermedio) y privkey.pem. Son enlaces simbólicos a archive/, así que las rutas nunca cambian entre renovaciones. Si quieres el trasfondo de qué es un certificado y por qué es gratis, lee certificados SSL gratuitos; esta guía trata sobre la herramienta.

Instalar certbot: primero snap, luego los paquetes de la distro

El proyecto certbot recomienda el paquete snap en Linux. Sigue la versión actual (5.x en 2026), incluye su propio Python, e instala un timer de systemd para la renovación. Elimina primero cualquier copia de la distro para que no haya dos certbots peleando por /etc/letsencrypt: sudo apt remove certbot, sudo dnf remove certbot o sudo yum remove certbot.

Los paquetes de la distro funcionan y son lo que ya tienen muchos servidores: sudo apt install certbot python3-certbot-nginx (o python3-certbot-apache) en Debian y Ubuntu, y los mismos nombres de paquete desde EPEL en RHEL, Rocky y Alma. La contrapartida es la antigüedad: una distribución LTS puede traer un certbot varias versiones mayores por detrás, lo que importa ahora que Let's Encrypt está acortando la vida de los certificados (ver la sección de renovación). Certbot también está publicado en PyPI y como imágenes Docker (certbot/certbot y una imagen por cada plugin de DNS) si prefieres esas opciones.

Tras instalar, certbot --version te dice qué tienes, y sudo certbot certificates lista todos los certificados que gestiona con sus dominios, fecha de caducidad y rutas de archivo.

Instalación recomendada en Linux (snap)

# remove an OS-packaged certbot first, if present
sudo apt remove certbot

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot

certbot --version
sudo certbot certificates

Emitir un certificado para nginx y Apache

Los plugins de nginx y Apache son el camino más corto. sudo certbot --nginx -d example.com -d www.example.com encuentra el bloque server cuyo server_name coincide, responde HTTP-01 a través de él, escribe ssl_certificate y ssl_certificate_key en ese bloque y recarga nginx. Las versiones recientes añaden por defecto la redirección de HTTP a HTTPS; --no-redirect la desactiva. --apache hace lo mismo con los virtual hosts. Ambos necesitan un server_name / ServerName que coincida con el dominio, o certbot no podrá saber qué bloque editar. ¿Eres nuevo con el propio servidor? Empieza por qué es nginx.

Webroot es la opción cuando quieres que certbot no toque tu configuración: escribe el archivo del challenge en un directorio que tu servidor en marcha ya sirve. certonly significa que añades tú mismo las dos líneas ssl_ una vez; las renovaciones luego simplemente reemplazan los archivos detrás de las mismas rutas.

Standalone levanta su propio pequeño servidor web en el puerto 80. Es para máquinas sin servidor web, o con uno que no es nginx ni Apache. El puerto 80 debe estar libre durante la emisión y cada renovación, así que detén el otro servidor en un hook: --pre-hook "systemctl stop haproxy" --post-hook "systemctl start haproxy".

Cada -d añade un nombre al mismo certificado, y el primero se convierte en el nombre del certificado. Para añadir un nombre más adelante, ejecuta el comando de nuevo con la lista completa más --cert-name example.com; certbot reemplaza el certificado antiguo en lugar de crear un segundo.

Las cuatro formas habituales de emitir (elige una)

# nginx: issue and install
sudo certbot --nginx -d example.com -d www.example.com

# Apache: issue and install
sudo certbot --apache -d example.com -d www.example.com

# webroot: issue only; your server keeps serving /.well-known/acme-challenge/
sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com

# standalone: certbot listens on :80 itself
sudo certbot certonly --standalone -d example.com

# then, in nginx, for the webroot/standalone case:
#   ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
#   ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Certificados wildcard con DNS-01

Let's Encrypt emite *.example.com solo mediante DNS-01. Un wildcard cubre un nivel (shop.example.com, no a.shop.example.com) y no cubre el dominio desnudo, así que pide ambos: -d example.com -d '*.example.com'. Pon el asterisco entre comillas para que la shell no lo expanda.

Con un plugin de DNS, certbot crea y borra los registros TXT a través de la API de tu proveedor de DNS, que es lo que hace que la renovación sea automática. Hay plugins oficiales para Cloudflare, Route 53, Google Cloud DNS, DigitalOcean, Linode, OVH, servidores RFC 2136 y otros, y plugins de terceros para muchos más. Con snap, primero permites que los plugins se ejecuten como root (sudo snap set certbot trust-plugin-with-root=ok) y luego instalas el snap del plugin. Mantén el archivo de credenciales en modo 600, y da al token de API el alcance más estrecho que ofrezca tu proveedor (en Cloudflare, *Zone: DNS: Edit* solo en esa zona).

Con --manual, certbot imprime el valor TXT y espera mientras lo añades a mano. Pedir example.com y *.example.com juntos pide dos valores TXT bajo el mismo nombre _acme-challenge.example.com; publícalos como dos registros separados. Compruébalo con dig +short TXT _acme-challenge.example.com antes de pulsar Intro. La pega: un certificado manual no se renueva automáticamente salvo que proporciones scripts --manual-auth-hook y --manual-cleanup-hook que hagan el trabajo de DNS, así que para cualquier cosa de larga duración usa un plugin.

Si tu proveedor de DNS no tiene API, puedes apuntar _acme-challenge.example.com con un registro CNAME a una zona que sí controlas; la CA sigue el CNAME y lee ahí el registro TXT.

Wildcard más apex con el plugin de DNS de Cloudflare (snap)

sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare

# /root/.secrets/cloudflare.ini  (chmod 600)
#   dns_cloudflare_api_token = <token with Zone:DNS:Edit>

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  -d example.com -d '*.example.com'

# by hand (no automatic renewal without hooks)
sudo certbot certonly --manual --preferred-challenges dns \
  -d example.com -d '*.example.com'

Renovación automática: timers, hooks y --dry-run

No escribes un cron job para certbot; el paquete ya lo hizo. El snap instala el timer de systemd snap.certbot.renew.timer, los paquetes de Debian y Ubuntu instalan certbot.timer, y algunos paquetes usan un archivo en /etc/cron.d/. El job ejecuta certbot renew dos veces al día, que renueva solo los certificados que toca renovar y termina sin más en los demás casos. Compruébalo con systemctl list-timers | grep certbot.

¿Cuándo toca renovar un certificado? Desde certbot 4.0, cuando queda menos de un tercio de su vida útil (la mitad, para certificados de 10 días o menos), y certbot también sigue las indicaciones de ACME Renewal Info (ARI) de la CA. Esto importa porque Let's Encrypt está acortando la vida útil: el perfil por defecto pasa de 90 a 64 días el 10 de febrero de 2027, y a 45 días en febrero de 2028. Una configuración que renueva con un cron fijo de "cada 60 días" se romperá; una que ejecuta certbot renew a diario no. Let's Encrypt también dejó de enviar correos de aviso de caducidad en 2025, así que nadie te avisará si la renovación falla en silencio: vigila tú mismo la fecha de caducidad del certificado.

Recarga el servidor tras la renovación. Los instaladores de nginx y Apache recargan por ti. Con webroot, standalone o un plugin de DNS, añade un deploy hook, que se ejecuta solo cuando se renovó de verdad un certificado. Ponlo en el comando de emisión (--deploy-hook, guardado en /etc/letsencrypt/renewal/<name>.conf) o deja un script ejecutable en /etc/letsencrypt/renewal-hooks/deploy/.

Prueba siempre con sudo certbot renew --dry-run. Ejecuta la renovación completa contra el entorno de staging de Let's Encrypt, con challenges reales, sin tocar tus certificados en producción ni usar los límites de tasa de producción.

Comprueba el timer, prueba la renovación, recarga nginx tras cada renovación

systemctl list-timers | grep certbot

sudo certbot renew --dry-run

# reload nginx whenever any certificate is renewed
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

# when does each certificate expire?
sudo certbot certificates

Límites de tasa de Let's Encrypt que sí puedes alcanzar

Los límites de Let's Encrypt son generosos para un uso normal y dolorosos durante una sesión de depuración. Los que muerden:

5 certificados por conjunto exacto de nombres cada 7 días. Emitir example.com + www.example.com cinco veces en una semana, por ejemplo al volver a ejecutar un script de aprovisionamiento o al borrar /etc/letsencrypt en cada arranque de un contenedor, bloquea ese conjunto exacto durante días. El error dice *too many certificates already issued for this exact set of identifiers* y da una hora de reintento. No hay forma de saltarse este límite. Cambiar el conjunto de nombres (añadir uno más) obtiene un límite nuevo, pero la solución real es mantener /etc/letsencrypt en almacenamiento persistente.

5 validaciones fallidas por nombre de host, por cuenta, cada hora. Un registro DNS equivocado más un bucle de reintentos agota esto en minutos.

50 certificados por dominio registrado cada 7 días, contados en todos los subdominios de example.com, y 300 pedidos nuevos por cuenta cada 3 horas. Las plataformas de hosting con muchos subdominios se topan primero con estos.

Las renovaciones se tratan con más indulgencia: una renovación que usa ARI, como hace el certbot actual, queda exenta de todos los límites, y una renovación normal del mismo conjunto de nombres queda exenta de los límites por dominio y por pedido.

La regla para los experimentos: añade --test-cert (alias --staging) o usa --dry-run. Staging tiene límites mucho más altos y emite certificados en los que los navegadores no confían, que es justo lo que quieres mientras consigues que el challenge funcione.

Errores comunes de certbot y cómo solucionarlos

Timeout al conectar / conexión rechazada en el puerto 80. HTTP-01 siempre empieza en el puerto 80, aunque tu sitio solo sirva HTTPS. Abre el puerto 80 en el firewall y en el security group de la nube; redirigirlo a HTTPS no pasa nada, porque la CA sigue las redirecciones. Si no puedes abrir el puerto 80, pasa a DNS-01.

Respuesta inválida / 404 en /.well-known/acme-challenge/. La petición llegó a un servidor, pero no al correcto o no al directorio correcto. Causas típicas: el registro A todavía apunta a un host antiguo, un balanceador de carga envía la petición a otro nodo, un bloque location o una reescritura captura la ruta, o -w apunta al webroot equivocado. Pruébalo tú mismo: crea un archivo bajo .well-known/acme-challenge/ y haz curl desde fuera por HTTP normal.

Un registro AAAA que apunta a otro sitio. Si el nombre tiene una dirección IPv6, Let's Encrypt valida primero por IPv6. Un registro AAAA obsoleto que responde desde otro servidor hace que la validación falle aunque IPv4 esté bien. Corrige o borra el registro AAAA; dig AAAA example.com lo muestra.

DNS problem: NXDOMAIN / no valid A records. El nombre todavía no resuelve. Espera la propagación, y comprueba el registro en un resolver externo, no solo en tu propia máquina.

Un registro CAA impide la emisión. Un registro CAA en el dominio (o en un padre) enumera las CA permitidas para emitir, y Let's Encrypt no está en la lista. Añade example.com. CAA 0 issue "letsencrypt.org", y issuewild también si tienes uno configurado para los wildcard. Más contexto en qué es el DNS.

TXT record incorrecto / no se encuentra el TXT. DNS-01 se comprobó antes de que el registro se propagara, o solo se publicó uno de los dos valores del wildcard. Sube el --dns-<provider>-propagation-seconds del plugin o espera más en modo manual.

Could not automatically find a matching server block. El plugin de nginx necesita un server_name igual al nombre solicitado. Añádelo, ejecuta nginx -t, y vuelve a intentarlo.

Too many certificates already issued. El límite de duplicados de arriba. Usa el certificado que ya tienes (certbot certificates), y prueba con --staging a partir de ahora.

Certbot en Windows: usa un cliente ACME nativo de Windows

Certbot ha descontinuado el soporte de Windows. El último instalador de Windows se publicó con certbot 2.9.0 en febrero de 2024, y la web de certbot ahora dirige a los usuarios de Windows a alternativas de la comunidad. Los instaladores antiguos que todavía se encuentran en sitios de descarga tienen años de retraso y no recibirán los cambios de renovación que está desplegando Let's Encrypt, así que no construyas nada sobre ellos.

Qué usar en su lugar depende del servidor:

IIS o cualquier servidor Windows: win-acme ha sido la opción habitual: una herramienta de línea de comandos que asocia el certificado en IIS, lo escribe en el almacén de certificados de Windows o en archivos PEM/PFX, y crea una tarea programada para la renovación. Su mantenedor ahora desarrolla simple-acme, descrito como un reemplazo compatible hacia atrás, así que revisa ese proyecto antes de un despliegue nuevo.

Automatización con PowerShell: Posh-ACME es un módulo de PowerShell con un amplio conjunto de plugins de DNS para los wildcard.

Prefieres una interfaz gráfica: Certify The Web es un cliente gráfico para IIS.

De verdad quieres certbot: ejecútalo dentro de WSL 2 para emitir, y luego exporta los archivos a Windows. Esto es práctico para certificados DNS-01 que copias a otro sitio, menos para un sitio IIS que necesita el enlace automático.

Nada de esto es una recomendación: todos son proyectos de terceros, así que lee su documentación actual antes de confiar en ellos.

Revocar y eliminar certificados

Revoca cuando la clave privada pueda haberse filtrado, o cuando ya no controles el dominio. Certbot necesita el nombre del certificado o el archivo del certificado, y un motivo: keycompromise, superseded, cessationofoperation, affiliationchanged o unspecified (el valor por defecto). Después de revocar, certbot ofrece borrar los archivos locales; responde que sí, o seguirá intentando renovar un certificado revocado. Si la clave se filtró, emite el reemplazo con una clave nueva, que es lo que hace certbot por defecto.

Elimina sin revocar cuando simplemente dejas de usar un certificado, por ejemplo tras mover un sitio: certbot delete --cert-name example.com lo quita de /etc/letsencrypt y de la renovación. Quita primero las líneas ssl_ correspondientes de la configuración del servidor, o nginx fallará al arrancar en la siguiente recarga.

Let's Encrypt ha dejado de ejecutar OCSP; los navegadores se enteran de las revocaciones mediante CRL, así que una revocación no es visible en todas partes al instante. Es otro motivo para mantener las claves privadas legibles solo por root.

Revoca un certificado comprometido, o elimina uno que ya no necesitas

sudo certbot revoke --cert-name example.com --reason keycompromise

sudo certbot delete --cert-name example.com

Detrás de un CDN: quién tiene el certificado

En cuanto un sitio se pone detrás de un CDN u otro proxy inverso, los visitantes ya no ven el certificado de tu origen. El edge termina el TLS con su propio certificado, y la conexión del edge a tu origen es un handshake aparte. Puedes mantener certbot en el origen para proteger ese segundo tramo, pero el certificado que comprueba el navegador es el del edge.

En CDN.com.tr, el certificado del edge lo gestiona Auto SSL: cada certificado es un certificado Let's Encrypt validado por dominio, sin cuota aparte. Apunta un nombre de host al edge con un CNAME y ese nombre obtiene su propio certificado, validado por HTTP. Delega tu DNS a CDN.com.tr y el dominio raíz obtiene un wildcard que cubre la raíz y cada subdominio de primer nivel, validado con un registro DNS. Se pide un certificado en cuanto el dominio está verificado y su DNS apunta a nosotros, y se renueva automáticamente 30 días antes de caducar, así que no hay ningún timer de certbot que vigilar.

¿Estás moviendo un sitio en producción? El asistente sin tiempo de inactividad emite el wildcard mediante un registro TXT en tu proveedor de DNS actual antes de que cambies, de forma parecida a una ejecución certbot --manual DNS-01, y como esa ejecución, no se renueva automáticamente mientras el DNS siga fuera de CDN.com.tr. Y si tienes un certificado OV o EV de otra CA, puedes subirlo y asociarlo a un nombre de host; recibe la misma política TLS que uno automático. La guía de TLS explica lo que negocia el edge, y HSTS es el siguiente paso en cuanto HTTPS sea fiable.

Preguntas frecuentes sobre certbot

¿Es gratis certbot?

Sí. Certbot es software de código abierto de la EFF, y los certificados de Let's Encrypt no cuestan nada. No pagas nada por certificado ni por renovación; los únicos límites son los límites de tasa de Let's Encrypt.

¿Cómo renuevo manualmente un certificado de certbot?

Ejecuta sudo certbot renew. Renueva todos los certificados que toque renovar y se salta los demás. Para forzar uno en concreto antes de tiempo, usa sudo certbot renew --cert-name example.com --force-renewal, pero no lo conviertas en costumbre: las renovaciones forzadas cuentan para el límite de certificados duplicados. Prueba primero con sudo certbot renew --dry-run.

¿Dónde guarda certbot los certificados?

En /etc/letsencrypt/live/<cert-name>/. Apunta tu servidor a fullchain.pem y privkey.pem. Son enlaces simbólicos a los archivos más recientes de /etc/letsencrypt/archive/, así que las rutas se mantienen iguales tras cada renovación. Haz copia de seguridad de todo el directorio /etc/letsencrypt, no solo de live/.

¿Puede certbot emitir un certificado wildcard?

Sí, pero solo mediante DNS-01: usa un plugin de DNS para tu proveedor, o --manual --preferred-challenges dns. Pide tanto example.com como '*.example.com', porque el wildcard no cubre el dominio desnudo. Los wildcard manuales no se renuevan solos salvo que añadas scripts de hook.

¿Funciona certbot en Windows?

Ya no. Certbot descontinuó el soporte de Windows en febrero de 2024; 2.9.0 fue la última versión con instalador para Windows. Usa un cliente ACME nativo de Windows como win-acme (o su sucesor simple-acme), Posh-ACME o Certify The Web, o ejecuta certbot dentro de WSL 2.

¿Cuál es la diferencia entre certbot --nginx y certbot certonly?

certbot --nginx obtiene el certificado y edita tu configuración de nginx para usarlo, añadiendo la redirección si lo permites. certbot certonly solo obtiene el certificado y lo guarda bajo /etc/letsencrypt/live/; tú añades las líneas ssl_certificate y un deploy hook para recargar nginx tras cada renovación.

¿Sigo necesitando certbot si mi sitio está detrás de un CDN?

No para el certificado que ven los visitantes: el CDN sirve el suyo propio en el edge. En CDN.com.tr, Auto SSL emite y renueva un certificado Let's Encrypt para cada dominio conectado. Puedes seguir usando certbot en el origen si el edge se conecta a él por HTTPS.