Seguridad

Let’s Encrypt con certbot: HTTPS gratis para tus servicios 2026

El primer certificado SSL que compré me costó USD 89 al año en un reseller y renovar cada 12 meses era una molestia administrativa. Olvidaba renovarlo, expiraba justo cuando tenía un post con tráfico alto, y pagar una factura anual por algo que OpenSSL genera gratis siempre se sintió mal. En 2016 renové un proyecto migrándolo a Let’s Encrypt y nunca más volví a pagar por un certificado.

Hoy Let’s Encrypt emite certificados válidos, reconocidos por todos los navegadores, gratis y renovables automáticamente cada 90 días a través de certbot (o los ACME clients nativos de Nginx/Apache). Esta guía recorre los tres casos que vas a encontrarte: Nginx como reverse proxy (lo más común), Apache nativo, y wildcard para subdominios ilimitados vía DNS-01 — con los errores reales que aparecen cuando el rate limit te pega o el challenge HTTP-01 no se resuelve.

TL;DR — Lo que vas a tener al final

  • Tiempo de setup: 15 minutos para el primer certificado, renovación automática cada 90 días sin intervención
  • Requisitos: Dominio propio con DNS accesible, servidor con Nginx o Apache, acceso root y puerto 80 libre para el challenge HTTP-01
  • Resultado: HTTPS válido en tu dominio, renovación automática mediante systemd timer o cron, y wildcard opcional si manejas muchos subdominios
  • Troubleshooting típico: Rate limit por dominio (solución: usar staging primero), puerto 80 bloqueado por ISP (solución: DNS-01 wildcard con un proveedor que lo soporte), renovación falla silenciosamente (solución: monitor con un curl al endpoint POST-hook que certbot expone)

Comprar un certificado TLS hace diez años costaba entre USD 50 y 500 por año, y renovar cada 12 meses era una molestia administrativa. Hoy Let’s Encrypt emite certificados válidos, reconocidos por todos los navegadores, gratis y renovables automáticamente cada 90 días. En esta guía te muestro cómo configurar certbot para Nginx o Apache, cómo obtener un wildcard para subdominios ilimitados, y cómo resolver los errores que aparecen cuando algo falla.


Índice

  1. [Cómo funciona Let’s Encrypt](#cómo-funciona-lets-encrypt)
  2. [Instalar certbot según tu servidor web](#instalar-certbot-según-tu-servidor-web)
  3. [Obtener el primer certificado](#obtener-el-primer-certificado)
  4. [Certificados wildcard y DNS-01](#certificados-wildcard-y-dns-01)
  5. [Renovación automática y monitoreo](#renovación-automática-y-monitoreo)
  6. [Troubleshooting común](#troubleshooting-común)
  7. [Conclusión](#conclusión)

Cómo funciona Let’s Encrypt

Let’s Encrypt es una autoridad certificante (CA) operada por ISRG (Internet Security Research Group), una organización sin fines de lucro respaldada por la EFF, Mozilla, Cisco y Akamai. Emite certificados X.509 válidos para TLS usando el protocolo ACME (Automatic Certificate Management Environment).

Lo importante a entender: Let’s Encrypt no puede emitir un certificado para un dominio que tú no controles. Para verificar el control, ACME ofrece tres desafíos:

  • HTTP-01: Let’s Encrypt hace un request HTTP a http://tudominio.com/.well-known/acme-challenge/TOKEN. Si responde 200 con el token correcto, validaste que controlás el dominio (porque solo el dueño del server puede responder por ese path). Es el método más simple y lo cubre certbot automáticamente.
  • DNS-01: creas un récord TXT específico en el DNS de tu dominio. Si Let’s Encrypt lo ve, validaste. Es el único método que funciona para certificados wildcard (*.tudominio.com) y el único que funciona para certificados cuando el server no tiene HTTP expuesto (caso típico: balanceadores, appliances, servicios internos).
  • TLS-ALPN-01: similar a HTTP-01 pero por TLS en puerto 443. Menos común, pero útil cuando no puedes usar HTTP (por ejemplo, si todo tu tráfico va por un reverse proxy en otro puerto).

Los certificados de Let’s Encrypt son válidos por 90 días. Esto es intencional: con expiración corta, si una clave privada se compromete, el daño es limitado. La clave se rota rápido. certbot por default configura la renovación automática cada 60 días (antes de los 90 de expiración), así que en condiciones normales nunca tienes que pensar en eso.

Antes de empezar, verifica tres cosas que tienen que estar en orden:

# 1. Que el dominio resuelve a tu server
dig +short tudominio.com
# Tiene que devolver la IP pública de tu server
# 2. Que el puerto 80 está accesible desde internet
# (prueba desde otra máquina o usa un servicio online)
curl -I http://tudominio.com
# HTTP/1.1 200 OK
# 3. Que no hay un firewall bloqueando
sudo ss -tlnp | grep ':80 '
# tcp   LISTEN 0  511  0.0.0.0:80  ...  *:*

Si el dominio no resuelve: el problema es DNS. verifica los records A/AAAA en tu proveedor (Cloudflare, Route53, NIC.ar, etc.). Propagación DNS puede tardar hasta 48h en casos raros, pero normalmente segundos.

Si el puerto 80 no responde desde afuera: hay un firewall (del cloud, del OS, del proveedor) bloqueando. Let’s Encrypt necesita llegar al puerto 80 sí o sí para HTTP-01. Si no puedes abrirlo (firewall corporativo, ISP que bloquea), tienes que usar DNS-01.

Si curl a localhost funciona pero desde afuera no: el server web está escuchando solo en 127.0.0.1. Cambiá el listen en la config de Nginx/Apache a 0.0.0.0 o la IP de la interfaz externa.


Instalar certbot según tu servidor web

certbot está empaquetado por la EFF y viene en los repos oficiales de las distros principales. Importante: el paquete certbot solo trae el cliente base; los plugins específicos para Nginx/Apache son paquetes separados.

Ubuntu/Debian con Nginx:

sudo apt update
sudo apt install certbot python3-certbot-nginx

python3-certbot-nginx es el plugin que le dice a certbot cómo editar la config de Nginx automáticamente para agregar el bloque HTTPS, redirigir HTTP a HTTPS, y recargar Nginx. Sin este plugin, certbot solo te da el certificado y tú tienes que configurar Nginx a mano.

Ubuntu/Debian con Apache:

sudo apt update
sudo apt install certbot python3-certbot-apache

RHEL/Fedora/CentOS Stream con Nginx:

sudo dnf install epel-release
sudo dnf install certbot python3-certbot-nginx

epel-release habilita el repositorio EPEL que contiene certbot. RHEL/Fedora no lo traen en los repos default porque la política de la distro es restrictiva con paquetes de terceros.

Si tu distro no tiene certbot en repos (Arch, Alpine, etc.) o quieres la versión más reciente siempre, puedes usar el instalador standalone de EFF:

sudo apt install snapd  # si tienes snap
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Si certbot --version devuelve error tras instalar: chequea que el binario esté en el PATH: which certbot. Si no está, sudo ln -s /snap/bin/certbot /usr/bin/certbot (Snap) o el path correspondiente al método de instalación. En Alpine (musl libc) a veces hay incompatibilidades con paquetes que esperan glibc; en ese caso usa el certbot standalone de pip en un virtualenv.

verifica que todo quedó bien antes de continuar. Esto confirma que certbot responde y que puedes ver ayuda (útil para encontrar opciones específicas):

certbot --version
# certbot 2.10.0
certbot --help | head -20
# usage: certbot [SUBCOMMAND] [options] ...
#
# Obtain, install, and renew certificates:
#   (default) run               Obtain & install a cert in your current webserver
#   certonly                    Obtain or renew a cert, but do not install it
#   renew                       Renew all previously obtained certificates that are near expiry
#   ...

Si certbot --help da error command not found pero acabás de instalar: en RHEL/Fedora a veces el PATH no se actualiza en la sesión actual. Cerrá y abrí la terminal, o hash -r para refrescar la caché de bash. Si sigues sin verlo, el binario está en /usr/bin/certbot o /usr/local/bin/certbot — sudo find / -name certbot 2>/dev/null lo encuentra.


Obtener el primer certificado

Ahora viene el paso principal: pedir el certificado. certbot tiene varios subcomandos según cuánto quieres que automatice:

  • certbot run (default): pide el certificado, edita la config de tu servidor web, redirige HTTP a HTTPS. El modo “automático” que usa el 90% de la gente.
  • certbot certonly: pide el certificado pero no toca la config de tu server. Útil cuando tienes configs custom que no quieres que certbot rompa.
  • certbot renew: renueva certificados existentes.

Caso 1: Nginx con un solo dominio (lo más común). certbot detecta Nginx automáticamente, te pregunta qué dominio cubrir, edita la config, y recarga:

sudo certbot --nginx -d tudominio.com -d www.tudominio.com

Las dos -d cubren el dominio con y sin www. certbot emite un solo certificado que sirve para ambos (Subject Alternative Names). Si te lo saltás y solo cubrís tudominio.com, los visitantes que entren por www.tudominio.com verán el error NET::ERR_CERT_COMMON_NAME_INVALID.

certbot te va a preguntar:

  • Email de contacto: para avisos de expiración y problemas críticos. usa uno que realmente leas. Let’s Encrypt manda avisos 20 días antes de expirar si la renovación automática falla.
  • Aceptar TOS: Y.
  • ¿Compartir email con EFF?: N está bien (es opcional, para estadísticas).
  • ¿Redirigir HTTP a HTTPS?: elegí 2 (redirect) para producción. 1 (no redirect) si quieres servir HTTP también.
sudo certbot --nginx -d tudominio.com -d www.tudominio.com
# Saving debug log to /var/log/letsencrypt/letsencrypt.log
# Enter email address (used for urgent renewal and security notices)
# (Enter 'c' to cancel): [email protected]
#
# Please read the Terms of Service at
# https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf
# (Y)es/(N)o: Y
#
# Would you be willing to share your email address with EFF?
# (Y)es/(N)o: N
#
# Which names would you like to activate HTTPS for?
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 1: tudominio.com
# 2: www.tudominio.com
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Select the appropriate numbers separated by commas and/or spaces, or leave input
# blank to select all options shown (Enter 'c' to cancel):
#
# Please choose whether or not to redirect HTTP traffic to HTTPS:
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 1: No redirect - Make no further changes to the webserver config
# 2: Redirect - Make all requests redirect to secure HTTPS access
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Select the appropriate number [1-2]: 2
#
# Congratulations! You have successfully enabled HTTPS on tudominio.com
# and www.tudominio.com

Si te aparece “Unable to find a virtual host listening on port 80”: certbot no encontró un server block en Nginx que responda por ese dominio. Casi siempre significa que el server_name en /etc/nginx/sites-enabled/tudominio.com no coincide con el dominio que pasaste, o que Nginx no está corriendo. sudo nginx -t valida la config; sudo systemctl status nginx confirma que está arriba.

Si falla con “Timeout during connect”: Let’s Encrypt no puede llegar a tu puerto 80. Las causas más comunes: firewall del cloud (AWS Security Group, GCP Firewall), firewall del OS (ufw, firewalld), o el proveedor bloqueando puertos bajos. verifica que curl http://tudominio.com desde otra máquina o servicio online (downforeveryoneorjustme.com, check-host.net) devuelva 200.

verifica que el certificado se instaló bien. La salida de certbot certificates lista todos los certificados gestionados por certbot en el sistema, con sus paths, dominios cubiertos, y fecha de expiración. Esta info te sirve para confirmar que se emitió, dónde está guardado el archivo, y cuánto falta para renovar:

sudo certbot certificates
# Certificate Name: tudominio.com
#     Serial Number: 03abc...
#     Domains: tudominio.com www.tudominio.com
#     Expiry Date: 2026-11-10T12:00:00+00:00 (VALID: 60 days)
#     Certificate Path: /etc/letsencrypt/live/tudominio.com/fullchain.pem
#     Private Key Path: /etc/letsencrypt/live/tudominio.com/privkey.pem

Los archivos importantes que ves:

  • /etc/letsencrypt/live/tudominio.com/fullchain.pem: certificado + cadena intermedia. Esto va en ssl_certificate de Nginx.
  • /etc/letsencrypt/live/tudominio.com/privkey.pem: clave privada. Esto va en ssl_certificate_key. Permisos 600, owner root.
  • /etc/letsencrypt/archive/tudominio.com/: archivos viejos por cada renovación. No los toques.

Si certbot certificates muestra “No certificates found”: la instalación no persistió. Casi siempre porque certonly se usó sin un instalador (--nginx, --apache). Volvé a correr el comando con --nginx o --apache, o usa certonly y configura Nginx a mano apuntando a los paths de arriba.

Testeá HTTPS manualmente. No te confíes solo en certbot: abrí https://tudominio.com en un navegador y verifica que aparece el candado. Después usa openssl para confirmar la cadena y la fecha:

echo | openssl s_client -connect tudominio.com:443 -servername tudominio.com 2>/dev/null | openssl x509 -noout -dates -subject -issuer
# subject=CN = tudominio.com
# issuer=C = US, O = Let's Encrypt, CN = R10
# notBefore=Aug 12 00:00:00 2026 GMT
# notAfter=Nov 10 00:00:00 2026 GMT

issuer=C = US, O = Let's Encrypt, CN = R10 confirma que el certificado fue emitido por Let’s Encrypt (R10 es el intermediate certificate de 2024). Si issuer muestra otra cosa (empresa comercial, “self-signed”), el certificado que estás viendo no es el de Let’s Encrypt.

Si el navegador muestra “El certificado no es de confianza” pero certbot certificates dice que está OK: probablemente Nginx está sirviendo un certificado viejo o el de otro virtual host. sudo nginx -T 2>/dev/null | grep ssl_certificate te muestra qué certificado está usando cada server block. Si hay un cert de otro dominio primero, Nginx sirve ese para todos los requests que matchean ese server_name.


Certificados wildcard y DNS-01

El wildcard (*.tudominio.com) cubre un dominio y todos sus subdominios de un solo nivel: api.tudominio.com, app.tudominio.com, blog.tudominio.com, etc. No cubre sub-subdominios (api.v2.tudominio.com) ni el dominio apex (tudominio.com sin subdominio). Para esos necesitas agregarlos explícitos.

El wildcard requiere DNS-01. ¿Por qué? Porque HTTP-01 verifica que controlás el server HTTP en el dominio — pero no puedes tener un server HTTP distinto para cada subdominio que quieres cubrir (imposible para infinitos). DNS-01 verifica que controlás la zona DNS entera, y un wildcard vale para todos los subdominios de esa zona.

certbot necesita hablar con tu proveedor DNS para crear el récord TXT automáticamente. Eso requiere un plugin específico del proveedor:

  • Cloudflare: python3-certbot-dns-cloudflare (Ubuntu) o python3-certbot-dns-cloudflare después de instalar pip.
  • Route53 (AWS): python3-certbot-dns-route53.
  • DigitalOcean: python3-certbot-dns-digitalocean.
  • Google Cloud DNS: python3-certbot-dns-google.
  • GoDaddy, Namecheap, NIC.ar: no hay plugins oficiales. tienes que hacer DNS-01 manual con --preferred-challenges dns y un hook, o usar otro cliente ACME como acme.sh.
sudo apt install python3-certbot-dns-cloudflare
# Crear archivo con credenciales API de Cloudflare
sudo mkdir -p /etc/letsencrypt/cloudflare
sudo nano /etc/letsencrypt/cloudflare/credentials.ini

El archivo credentials.ini lleva tu API token de Cloudflare. Importante: los permisos tienen que ser 600, sino certbot se queja porque la API key queda legible para otros usuarios del sistema, lo que es un agujero de seguridad. El token tiene que tener permisos de Edit DNS para la zona específica, no el global token:

dns_cloudflare_api_token = tu_api_token_aqui
sudo chmod 600 /etc/letsencrypt/cloudflare/credentials.ini
sudo certbot certonly 
  --dns-cloudflare 
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini 
  -d tudominio.com 
  -d "*.tudominio.com"

certbot va a:

  1. Crear un récord TXT en _acme-challenge.tudominio.com con un token random.
  2. Esperar a que se propague (30-60 segundos).
  3. Pedirle a Let’s Encrypt que valide el récord.
  4. Si está, emitir el certificado wildcard.
  5. Borrar el récord TXT (cleanup).

El certificado emitido cubre tudominio.com y *.tudominio.com. Lo configuras en Nginx igual que cualquier otro cert, pero recuerda que en Nginx los certificados wildcard necesitan que el server_name sea específico — no puedes tener un default server con un wildcard y pretender que cubra todos los dominios.

server {
    listen 443 ssl http2;
    server_name api.tudominio.com;
    ssl_certificate /etc/letsencrypt/live/tudominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tudominio.com/privkey.pem;
    # ... resto de config
}

Si el wildcard no cubre tudominio.com: tienes que agregar el apex explícito. Por eso pasamos dos -d en el comando: uno para el dominio y otro para *.tudominio.com. Si solo pasaste el wildcard, el apex no queda cubierto.

Si la propagación DNS falla y certbot timeoutea: el plugin de Cloudflare tiene un timeout de 60 segundos. Si tu zona DNS tiene TTL alto o el proveedor DNS es lento, puede fallar. Solución: pasá --dns-cloudflare-propagation-seconds 120 para darle más tiempo, o --dns-cloudflare-propagation-seconds 0 para no esperar (asumís que se propaga rápido, lo que es razonable en Cloudflare porque sus cambios se replican globalmente en segundos).

Si te dice “Error adding TXT record”: las credenciales no tienen permisos. En Cloudflare, el token tiene que tener Zone.DNS:Edit para la zona específica. El Global API Key funciona pero es más riesgoso (acceso total a la cuenta). No uses el Global API Key en servidores de producción — si el server se compromete, el atacante tiene control total de tu DNS.


Renovación automática y monitoreo

certbot instala un timer de systemd o un cron job que corre dos veces por día y renueva automáticamente cualquier certificado que esté a menos de 30 días de expirar. verifica que está activo:

sudo systemctl list-timers | grep certbot
# Wed 2026-08-13 03:42:00 UTC  11h Wed 2026-08-12 ... certbot.timer certbot.service

Si no ves el timer, activa el servicio de renewal:

sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

El timer corre certbot renew que:

  1. Lee /etc/letsencrypt/renewal/*.conf para saber qué certificados gestionar.
  2. Para cada certificado a menos de 30 días de expirar, intenta renovar.
  3. Si el server web está corriendo, usa el método original (HTTP-01) o el plugin (DNS-01 con Cloudflare) para revalidar.
  4. Si la renovación funciona, reemplaza el cert y corre el deploy hook (si configuraste uno).

Si la renovación falla silenciosamente: el cron job loguea a /var/log/letsencrypt/letsencrypt.log y, en caso de error, manda un email a la dirección que configuraste. Por eso es importante pasar un email real al certbot --nginx inicial — sin email, no te enterás si algo falla.

Testeá la renovación sin esperar 60 días. --dry-run simula todo el proceso (incluyendo contactar Let’s Encrypt) pero no emite ni reemplaza ningún certificado. Útil para confirmar que tu config de renovación va a funcionar cuando llegue el momento:

sudo certbot renew --dry-run
# Saving debug log to /var/log/letsencrypt/letsencrypt.log
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Processing /etc/letsencrypt/renewal/tudominio.com.conf
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Account registered.
# Simulating renewal of an existing certificate for tudominio.com and www.tudominio.com
#
# Congratulations, all simulated renewals succeeded

Si --dry-run falla con “Connection refused”: el server web no está corriendo o no escucha en el puerto 80. Certbot tiene que poder servir el challenge HTTP-01. sudo systemctl restart nginx (o apache2) y volvé a probar.

Si --dry-run falla con “DNS problem: NXDOMAIN”: el dominio ya no apunta a tu server. verifica con dig +short tudominio.com — si devuelve la IP vieja o nada, tu DNS cambió.

Para monitoreo serio en producción, agregá un check externo que verifique la fecha de expiración y alerte con tiempo:

#!/bin/bash
# check_ssl_expiry.sh - ejecuta en cron diario
DOMAIN="tudominio.com"
EXPIRY=$(echo | openssl s_client -connect ${DOMAIN}:443 -servername ${DOMAIN} 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "${EXPIRY}" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt 14 ]; then
    echo "ALERTA: certificado ${DOMAIN} expira en ${DAYS_LEFT} días" | mail -s "SSL expiring soon" [email protected]
fi

openssl s_client -connect ... -servername hace el handshake TLS y devuelve el certificado. -enddate extrae solo la fecha de expiración. La conversión a epoch permite calcular días restantes sin problemas de formato. Si EXPIRY está vacío: el server no respondió TLS o el puerto 443 está cerrado — distinto problema que expiración, pero también es alerta.

Si la renovación automática falla repetidamente: revisa /var/log/letsencrypt/letsencrypt.log (o journalctl -u certbot.service si usas timer). Las causas más comunes: cambios en el DNS que invalidaron HTTP-01, expiración del API token de Cloudflare, el server web dejó de arrancar entre la emisión del cert y el reload, o se llenó el disco donde está /var/log/letsencrypt/.


Troubleshooting común

“Challenge failed for domain”

Let’s Encrypt no pudo validar el dominio. Pasos para diagnosticar:

# 1. verifica que el dominio resuelve a tu server
dig +short tudominio.com
# 2. verifica que el puerto 80 responde
curl -I http://tudominio.com
# 3. Simulá el challenge manualmente
sudo certbot certonly --webroot -w /var/www/html -d tudominio.com --dry-run
# 4. Si usas Cloudflare, verifica que el modo es "DNS only" (gris), no "Proxied" (naranja)

“Mode proxied en Cloudflare” es la causa número uno de challenges fallidos. Cuando Cloudflare está en modo proxied, el request a tudominio.com lo termina Cloudflare (que tiene su propio certificado), no tu server. Let’s Encrypt intenta validar tu server pero el path del challenge no llega porque Cloudflare lo intercepta. Solución: DNS only (gris) para el dominio durante la emisión, después puedes volver a proxied si quieres.

“Rate limit exceeded”

Let’s Encrypt tiene rate limits generosos pero finitos:

  • 50 certificados por dominio por semana.
  • 5 duplicados por semana.
  • 5 cuentas nuevas por IP cada 3 horas.

Si llegaste al límite, espera. Para evitar llegar, no uses --force-renewal a mano seguido — certbot ya renueva automáticamente a los 60 días. Solo forzá renewal si cambiaste la config (agregaste un dominio nuevo, por ejemplo).

“Server only speaks HTTP, not HTTPS”

Nginx está configurado pero el bloque server { listen 443 ssl; ... } falta o tiene errores. sudo nginx -t valida la config; sudo systemctl status nginx confirma que arrancó. Si ves nginx: [emerg] no "ssl_certificate" is defined, falta el path al cert.

“OpenSSL: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure”

El cliente (openssl, curl, navegador) y el server no se ponen de acuerdo en una versión de TLS. Los navegadores modernos (Chrome desde 2024, Firefox desde 2024) ya no negocian TLS 1.0 ni 1.1. Tu Nginx tiene que tener ssl_protocols TLSv1.2 TLSv1.3;. TLS 1.3 es preferible (más rápido, más seguro); 1.2 aceptable para compatibilidad. TLS 1.0 y 1.1 son inseguros y los navegadores los rechazan. (HTTP-01 de Let’s Encrypt no usa TLS — solo HTTPS port 443 para ACME.)

“Cert has expired” en el navegador pero certbot dice que está OK

Nginx cacheó el cert viejo. sudo nginx -s reload lo recarga, pero si la renovación automática se hizo y Nginx no recargó, hay un mismatch. verifica el deploy hook: /etc/letsencrypt/renewal-hooks/deploy/ debería tener un script que recarga Nginx después de renovar. certbot lo crea automáticamente cuando usas --nginx; si usas --certonly, lo tienes que crear a mano:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Si tu distro usa apache2 en vez de nginx: el mismo principio pero systemctl reload apache2.

“Permission denied on /var/lib/letsencrypt/”

certbot necesita escribir en ese directorio para mantener el estado de la cuenta ACME. Si lo corres como root (con sudo), no hay problema. Si lo corres como usuario normal, falla. Siempre corré certbot con sudo salvo que hayas configurado un certbot específico para usuario (poco común).


Conclusión

Let’s Encrypt con certbot es la forma estándar de tener HTTPS en 2026. La instalación inicial toma 5 minutos, la renovación automática está garantizada por el timer de systemd, y los certificados son válidos en todos los navegadores. Para el caso simple (un dominio, Nginx), certbot --nginx -d dominio.com resuelve todo. Para escenarios más complejos (wildcard, múltiples dominios, servidores sin HTTP expuesto), DNS-01 con un plugin de tu proveedor DNS es la salida. Próximos pasos: verificar que el timer está activo, hacer un --dry-run de renovación, agregar monitoreo de fecha de expiración, y considerar endurecer la config TLS de Nginx (HSTS, OCSP stapling, cipher suites modernas).

Lee también: [Hardening SSH: 7 cambios de seguridad](/hardening-ssh-7-cambios-seguridad/) si necesitas asegurar el acceso al server además de HTTPS, o [Configurar firewall Linux con nftables](/configurar-firewall-linux-nftables-reemplazo-iptables/) para entender el firewall que protege el puerto 443.

Preguntas frecuentes

¿Por qué Let’s Encrypt con certbot: HTTPS gratis para tus servicios 2026 es relevante para sysadmins Linux?

Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.

¿Qué necesito para empezar con Let’s Encrypt con certbot: HTTPS?

Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.

¿Cuáles son los errores más comunes con Let’s Encrypt con certbot: HTTPS?

Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.

¿Cuándo usar Let’s Encrypt con certbot: HTTPS y cuándo una alternativa?

Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.

¿Cómo migro desde una configuración previa a Let’s Encrypt con certbot: HTTPS?

Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.

Lee también

Alfonso Moreno | Sysadmin Senior

Soy Alfonso, sysadmin senior con RHCE y más de 10 años administrando sistemas Linux para empresas y proyectos personales. Me especializo en infraestructura, redes, virtualización, monitoring, automation y self-hosting. Sobre SoyLinux.com SoyLinux.com es un blog técnico en español sobre Linux, software libre y self-hosting. Lo mantengo en mi tiempo libre. Áreas de expertise - Linux server administration: RHEL, CentOS, Rocky, Alma, Fedora, Debian, Ubuntu - Network services: Postfix, BIND, Samba, NFS, Squid - Virtualización y containers: KVM, Proxmox, Docker, Podman - Monitoring: Prometheus, Grafana, Zabbix - Automation: Ansible, Bash scripting - Self-hosting: Vaultwarden, Nextcloud, Jellyfin, Immich, Homelab Contacto - Email: [email protected]

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *