Correo electrónico: renovación de certificado TLS — evitar que SMTP/IMAP falle el día de la renovación

¿Te fue útil?

El día de la renovación de un certificado es cuando “nada cambió” se convierte en un incendio de cuatro alarmas. El correo es especial en ese sentido:
el resto de tu stack puede tolerar un bache, pero los reintentos SMTP, los clientes IMAP gritan, y los ejecutivos redescubren
lo que significa “bandeja de salida”.

La buena noticia: mantener SMTP/IMAP estable durante la renovación de un certificado TLS es en su mayoría mecánica aburrida. La mala noticia:
sólo funciona si haces las partes aburridas a propósito, y pruebas exactamente las cosas que realmente rompen.

Un modelo mental para producción: qué puede fallar, dónde y por qué

Renovar un certificado TLS suena como un simple intercambio: reemplazar un archivo, reiniciar un demonio, listo.
Los servidores de correo castigan ese optimismo porque hay múltiples contextos TLS y múltiples clientes,
y no todos se comportan igual.

SMTP no es un solo protocolo, son tres modos de despliegue

La mayoría de los operadores de correo ejecutan todos estos al mismo tiempo:

  • SMTP con STARTTLS (puerto 25) para entrega servidor a servidor. TLS oportunista, pero aún exigente con cadenas y nombres según la política.
  • Submission con STARTTLS (puerto 587) para usuarios/clientes. Usualmente validación estricta, especialmente en clientes móviles/escritorio modernos.
  • SMTPS (puerto 465) TLS implícito. Aún común; los clientes esperan un handshake limpio de inmediato.

Puedes renovar un certificado y “probar el puerto 25” y aun así romper a la mitad de tus usuarios en 587.
O viceversa. Pregúntame cómo lo sé. En realidad no lo hagas; forma carácter, y probablemente ya tienes suficiente carácter.

IMAP/POP pertenecen al terreno de “conexiones de larga duración”

Dovecot (o tu demonio IMAP/POP preferido) suele mantener muchas sesiones TLS abiertas.
Un intercambio de certificado no renegocia automáticamente. Algunos clientes seguirán funcionando hasta que se reconecten; otros se reconectarán
agresivamente y empezarán a fallar en ráfagas. Eso hace que parezca “problemas intermitentes de red” hasta que lo correlaciones
con el evento de renovación.

El intercambio de archivos no es el despliegue

Este es el error conceptual más común: “certbot renovó, así que hemos terminado.”
Certbot (o cualquier cliente ACME) escribe archivos. Tus demonios no los vuelven a leer mágicamente a menos que recargues/reinicies,
y aun así sólo si tu configuración apunta a las rutas correctas. Añade enlaces simbólicos y montajes de contenedores y obtendrás el clásico:
“El certificado en disco es nuevo pero el servicio sigue sirviendo el antiguo.”

Cómo se manifiesta realmente un “fallo”

Verás uno de estos:

  • Fallos de handshake (clave incorrecta, cadena rota, protocolo/cifrados no soportados, o permisos malos).
  • Desajuste de nombre de host (CN/SAN equivocado, mapeo de vhost incorrecto, SNI erróneo, o clientes apuntando a un nombre distinto al que probaste).
  • Fallos por políticas (MTA-STS aplicado, discrepancia DANE, certificados fijados en clientes, proxies corporativos que hacen “inspección”).
  • Fallos operativos (no se hizo la recarga, deriva de configuración, permisos de archivo incorrectos, SELinux/AppArmor bloqueando lecturas).

Un encuadre útil (ligeramente paranoico): trata una renovación TLS como un pequeño despliegue de configuración que afecta a cada conexión entrante y saliente.
No “renuevas un certificado.” Despliegas un nuevo artefacto de confianza en un sistema distribuido.

Una cita que sigue vigente en operaciones: “La esperanza no es una estrategia.” — Gene Kranz

Hechos interesantes y contexto histórico (sí, importa)

El comportamiento TLS en correo es el resultado de décadas de adaptaciones. Un poco de historia aclara por qué tu cambio “simple” puede desencadenar
20 comportamientos diferentes de clientes.

  1. STARTTLS se añadió más tarde. SMTP es anterior a TLS; STARTTLS es una extensión añadida a un protocolo más antiguo, así que “oportunista” se volvió la vibra por defecto.
  2. El puerto 465 fue “deprecado”, y luego regresó. SMTPS fue en su día no oficial, luego se prefirió submission en 587, y ahora 465 vuelve a recomendarse ampliamente para TLS implícito.
  3. Las cadenas de certificados se acortaron con el tiempo. Muchos entornos pasaron de cadenas largas con cross-sign a raíces/intermedios más limpias; clientes antiguos a veces requieren el intermediario “correcto”.
  4. Let’s Encrypt aceleró los ciclos de renovación. Los certificados de corta duración normalizaron la automatización, pero también normalizaron el “ups, olvidamos el hook de recarga”.
  5. IMAP IDLE hace que las fallas parezcan aleatorias. Las conexiones de larga duración implican que los problemas de certificado aparecen durante tormentas de reconexión, no exactamente en el momento de la renovación.
  6. La eliminación de TLS 1.0/1.1 fue un cambio rompedor. Endurecer las versiones de protocolo mejoró la seguridad, pero los clientes de correo heredados (y appliances) reaccionaron mal.
  7. MTA-STS y TLS-RPT cambiaron incentivos. El TLS servidor a servidor pasó de “agradable de tener” a “algunos dominios te rechazarán” si fallas la política.
  8. DANE existe y está poco usado. Puede forzar TLS a nivel SMTP usando DNSSEC, pero también hace que los errores de renovación sean instantáneamente obvios para pares estrictos.

Broma #1: La renovación TLS es como cambiar una rueda mientras el coche avanza—excepto que el coche también está entregando correos ejecutivos y juzgándote en silencio.

Guía de diagnóstico rápido (primeras/segundas/terceras comprobaciones)

Cuando “el TLS del correo está roto”, necesitas una vía rápida hacia el cuello de botella. No empieces por redeplegar todo.
Empieza por aislar qué servicio, qué puerto, qué nombre, qué certificado.

Primero: identifica la superficie que falla

  • ¿Qué protocolo? SMTP entrante (25), submission (587), SMTPS (465), IMAPS (993), POP3S (995).
  • ¿Qué nombre de host? mail.example.com vs smtp.example.com vs el apex del dominio.
  • ¿Qué tipo de cliente? Servidores de Gmail, Outlook de escritorio, iOS Mail, una impresora, un appliance SIEM.

Decisión: si sólo un puerto falla, tienes un problema de mapeo/configuración/recarga. Si todos los puertos fallan, sospecha permisos de archivos,
desajuste de clave o corrupción de cadena.

Segundo: obtén el certificado que se sirve desde la red

No confíes todavía en lo que hay en disco. Confía en lo que realmente se sirve.

Decisión: si el certificado servido es viejo, tu recarga no se aplicó. Si es nuevo pero inválido, es cadena/nombre/clave.

Tercero: confirma localmente la cadena y el emparejamiento de la clave

Si el handshake de red falla, confirma que la clave privada coincide con el certificado y que la cadena completa es correcta.

Decisión: el desajuste significa archivos mal conectados; problemas de cadena significan que necesitas el archivo intermediate/fullchain correcto en la configuración.

Cuarto: lee los logs del demonio con propósito

Postfix y Dovecot típicamente te dicen exactamente qué no pueden cargar. La gente simplemente no lee las líneas que importan.
Busca “cannot load,” “no start line,” “permission denied,” “key values mismatch.”

Quinto: verifica la capa de políticas (MTA-STS/DANE) si sólo fallan ciertos dominios

Si la mayoría de las entregas tienen éxito pero algunos dominios rebotan con “TLS requerido,” no estás ante un “TLS caído”,
estás ante un “cumplimiento TLS fallido.” Problema distinto, arreglo distinto.

Tareas prácticas: comandos, salidas y decisiones (12+)

A continuación hay tareas operativas reales. Cada una incluye: el comando, un fragmento realista de salida,
qué significa la salida y qué debes decidir después.

Tarea 1: Confirmar la expiración y los SANs del certificado en disco

cr0x@server:~$ openssl x509 -in /etc/letsencrypt/live/mail.example.com/fullchain.pem -noout -dates -subject -ext subjectAltName
notBefore=Jan  1 00:12:03 2026 GMT
notAfter=Apr  1 00:12:02 2026 GMT
subject=CN = mail.example.com
X509v3 Subject Alternative Name:
    DNS:mail.example.com, DNS:smtp.example.com, DNS:imap.example.com

Significado: Este certificado es actualmente válido y cubre múltiples nombres de host.

Decisión: Si el nombre que falla no está en SANs, detente. Emite el certificado correcto (o añade el nombre),
no intentes “soluciones” como deshabilitar la verificación de nombres.

Tarea 2: Verificar que la clave privada coincide con el certificado (comprobación de módulo)

cr0x@server:~$ openssl x509 -noout -modulus -in /etc/letsencrypt/live/mail.example.com/cert.pem | openssl md5
MD5(stdin)= 9c0a0c7d5d0f4f1d0c1b1c1f3b7a2a7e
cr0x@server:~$ openssl rsa -noout -modulus -in /etc/letsencrypt/live/mail.example.com/privkey.pem | openssl md5
MD5(stdin)= 9c0a0c7d5d0f4f1d0c1b1c1f3b7a2a7e

Significado: El certificado y la clave emparejan.

Decisión: Si los hashes difieren, estás sirviendo un certificado con la clave equivocada. Corrige el cableado y redepliega; no reinicies servicios repetidamente esperando que se resuelva.

Tarea 3: Ver qué piensa Postfix que son sus archivos TLS

cr0x@server:~$ postconf -n | egrep 'smtpd_tls_cert_file|smtpd_tls_key_file|smtpd_tls_CAfile|smtpd_tls_chain_files|smtp_tls_security_level'
smtp_tls_security_level = may
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem

Significado: Postfix está configurado para presentar fullchain.pem.

Decisión: Si estas rutas no apuntan a donde crees, arregla la configuración primero, luego recarga. Si usas chroot, asegúrate de que Postfix pueda ver estas rutas desde dentro.

Tarea 4: Comprobar las rutas TLS en la configuración de Dovecot

cr0x@server:~$ doveconf -n | egrep 'ssl =|ssl_cert|ssl_key|ssl_min_protocol|ssl_cipher_list'
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_min_protocol = TLSv1.2

Significado: Dovecot lee la cadena completa y requiere TLS.

Decisión: Si Dovecot apunta a cert.pem en lugar de fullchain.pem, a menudo romperás clientes que no obtienen intermedios. Usa la cadena completa a menos que tengas una razón probada para no hacerlo.

Tarea 5: Probar STARTTLS en el puerto 25 desde la perspectiva de un cliente

cr0x@server:~$ openssl s_client -starttls smtp -connect mail.example.com:25 -servername mail.example.com -showcerts -verify_return_error </dev/null
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = mail.example.com
verify return:1
250 SMTPUTF8

Significado: TLS se verifica limpiamente, y las capacidades SMTP se anuncian después de STARTTLS.

Decisión: Si la verificación falla, lee la primera línea “verify error”. Si es “unable to get local issuer,” tu cadena es incorrecta. Si es “hostname mismatch,” tus SANs están mal o SNI está mal enrutado.

Tarea 6: Probar el puerto de submission 587 con STARTTLS y anuncio de AUTH

cr0x@server:~$ openssl s_client -starttls smtp -connect mail.example.com:587 -servername mail.example.com -crlf -quiet </dev/null | head -n 12
depth=0 CN = mail.example.com
verify return:1
250-mail.example.com
250-PIPELINING
250-SIZE 52428800
250-STARTTLS
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250 8BITMIME

Significado: El certificado verifica y el servidor anuncia AUTH (típico en submission).

Decisión: Si 25 funciona pero 587 falla, probablemente tengas un listener separado, configuración de certificado separada, o un proceso/contenedor distinto sirviendo 587.

Tarea 7: Probar TLS implícito en el puerto 465

cr0x@server:~$ openssl s_client -connect mail.example.com:465 -servername mail.example.com -verify_return_error </dev/null | egrep 'subject=|issuer=|Verify return code'
subject=CN = mail.example.com
issuer=C = US, O = Let's Encrypt, CN = R3
Verify return code: 0 (ok)

Significado: El handshake SMTPS está limpio.

Decisión: Si 465 falla pero 587 funciona, sospecha una pila TLS diferente (por ejemplo, definición de servicio separada, configuración heredada, o un LB que termina TLS sólo para 465).

Tarea 8: Probar IMAPS (993) y verificar el certificado presentado

cr0x@server:~$ openssl s_client -connect mail.example.com:993 -servername mail.example.com -verify_return_error </dev/null | egrep 'subject=|issuer=|Verify return code'
subject=CN = mail.example.com
issuer=C = US, O = Let's Encrypt, CN = R3
Verify return code: 0 (ok)

Significado: IMAPS presenta el certificado y la cadena esperados.

Decisión: Si IMAPS falla pero SMTP funciona, céntrate en Dovecot: permisos de archivos, recarga, o una ruta ssl_cert separada.

Tarea 9: Confirmar qué certificado cargó realmente Postfix (guiado por logs)

cr0x@server:~$ sudo journalctl -u postfix -n 200 --no-pager | egrep -i 'tls|certificate|key|error' | tail -n 12
Jan 04 10:21:18 mail postfix/smtpd[21456]: warning: TLS library problem: error:0A00018F:SSL routines::ee key too small
Jan 04 10:21:18 mail postfix/smtpd[21456]: fatal: TLS library initialization failed
Jan 04 10:21:19 mail postfix/master[1023]: warning: process /usr/lib/postfix/sbin/smtpd pid 21456 exit status 1
Jan 04 10:21:19 mail postfix/master[1023]: warning: /usr/lib/postfix/sbin/smtpd: bad command startup -- throttling

Significado: La librería TLS rechazó el tamaño de la clave (común después de endurecimientos de seguridad o cuando alguien instaló la clave equivocada).

Decisión: Reemite un par cert/clave que cumpla con la política de OpenSSL (típicamente RSA 2048+ o ECDSA). No aflojes los niveles de seguridad de OpenSSL sólo para “hacer que funcione.”

Tarea 10: Confirmar que Dovecot puede leer los archivos (permisos y la realidad SELinux-ish)

cr0x@server:~$ sudo -u dovecot test -r /etc/letsencrypt/live/mail.example.com/privkey.pem && echo OK || echo NO
OK
cr0x@server:~$ sudo -u dovecot test -r /etc/letsencrypt/live/mail.example.com/fullchain.pem && echo OK || echo NO
OK

Significado: El usuario dovecot puede leer ambos archivos.

Decisión: Si obtienes NO, arregla permisos/propiedad de archivos o usa un paso de copia de despliegue a un directorio que el servicio posea. Considera también sistemas MAC (SELinux/AppArmor): “legible” en permisos Unix no garantiza permitido.

Tarea 11: Recargar daemons de forma segura y verificar que permanecen activos

cr0x@server:~$ sudo systemctl reload postfix
cr0x@server:~$ sudo systemctl reload dovecot
cr0x@server:~$ systemctl is-active postfix dovecot
active
active

Significado: Ambos servicios aceptaron la recarga y permanecen activos.

Decisión: Si la recarga falla o el servicio queda inactivo, detente y revierte a los archivos de certificado conocidos buenos. Un despliegue de certificados que tumba el demonio es peor que un certificado expirado por varios órdenes de magnitud.

Tarea 12: Verificar desde el namespace de red del host (truco de contenedores/LB)

cr0x@server:~$ openssl s_client -starttls smtp -connect 127.0.0.1:587 -servername mail.example.com -verify_return_error </dev/null | egrep 'subject=|Verify return code'
subject=CN = mail.example.com
Verify return code: 0 (ok)

Significado: Localmente el servicio es correcto. Si las pruebas externas fallan, sospecha balanceadores de carga, proxies, NAT, o un nodo distinto sirviendo tráfico.

Decisión: Compara huellas (fingerprints) locales vs externas; si difieren, tienes split-brain entre instancias.

Tarea 13: Confirmar la huella del certificado servido (útil para comparar nodos)

cr0x@server:~$ echo | openssl s_client -connect mail.example.com:993 -servername mail.example.com 2>/dev/null | openssl x509 -noout -fingerprint -sha256
sha256 Fingerprint=6B:12:8E:3B:40:65:8D:29:42:0E:AD:AF:47:3F:9A:5C:0C:52:6A:0F:84:62:26:25:13:73:4C:CA:19:1C:0E:8A

Significado: Este es el certificado real servido en ese endpoint ahora mismo.

Decisión: Ejecuta el mismo comando contra cada nodo o target VIP. Si las huellas difieren, arregla tu pipeline de despliegue o la membresía del pool del LB antes de hacer cualquier otra cosa.

Tarea 14: Validar que el archivo de cadena sea estructuralmente sano

cr0x@server:~$ awk 'BEGIN{c=0} /BEGIN CERTIFICATE/{c++} END{print c}' /etc/letsencrypt/live/mail.example.com/fullchain.pem
2

Significado: fullchain.pem contiene dos certificados (leaf + intermediario), lo que es típico.

Decisión: Si esto imprime 1, podrías estar sirviendo sólo la hoja. Si imprime un número sorprendente, alguien concatenó certificados extra y confundió a clientes exigentes.

Tarea 15: Comprobar expiraciones próximas en todos los nombres servidos (seguro barato)

cr0x@server:~$ for host in mail.example.com smtp.example.com imap.example.com; do
> echo -n "$host 587: "
> echo | openssl s_client -starttls smtp -connect $host:587 -servername $host 2>/dev/null \
> | openssl x509 -noout -enddate
> done
mail.example.com 587: notAfter=Apr  1 00:12:02 2026 GMT
smtp.example.com 587: notAfter=Apr  1 00:12:02 2026 GMT
imap.example.com 587: notAfter=Apr  1 00:12:02 2026 GMT

Significado: Todos los nombres están sirviendo un certificado consistente con la misma fecha de expiración.

Decisión: Si un nombre muestra una fecha distinta, tienes una discrepancia de enrutamiento/vhost o un nodo obsoleto.

Tres mini-historias corporativas (anonimizadas, dolorosamente plausibles)

Mini-historia 1: El corte causado por una suposición equivocada (el mito “fullchain es opcional”)

Una empresa SaaS mediana ejecutaba Postfix + Dovecot en un par de VMs detrás de un balanceador TCP. Renovaron con ACME,
y en un commit de limpieza, un ingeniero “simplificó” la configuración apuntando tanto Postfix como Dovecot a cert.pem
en lugar de fullchain.pem. La suposición era razonable: “los clientes pueden obtener los intermedios.”

El primer indicio no fue una caída total. Fueron tickets de soporte: “Outlook dice que el certificado no es de confianza.”
Luego un comercial no pudo conectar en una Wi‑Fi de hotel. Luego la pasarela on‑prem de un socio dejó de aceptar entregas
con un error de validación TLS. La mayoría de los otros clientes siguieron funcionando, porque los stacks modernos a menudo construyen cadenas faltantes usando
intermediarios en caché.

Ops pasó horas persiguiendo “inestabilidad de red” porque los síntomas variaban por cliente y ubicación. Las comprobaciones de salud del balanceador
estaban verdes (sólo comprobaban TCP). Las colas de correo crecieron lentamente, luego se dispararon cuando los reintentos se acumularon. Nadie lo correlacionó con
la renovación porque “el certificado es válido” y la fecha de expiración estaba en el futuro.

La solución fue una línea: servir fullchain.pem. Pero la lección quedó: las suposiciones sobre el comportamiento de los clientes no pertenecen
a correo en producción. La cadena que envías es la cadena de la que eres responsable.

Mini-historia 2: La optimización que salió mal (evitar recargas como táctica de “estabilidad”)

Un equipo IT empresarial tenía una cultura estricta de control de cambios, y les habían quemado los reinicios.
Así que declararon un nuevo estándar: renovar certificados automáticamente, pero nunca recargar los demonios de correo automáticamente.
“Lo haremos durante la ventana mensual,” decían, y sonaba maduro.

Durante semanas, todo parecía bien. Los certificados se renovaban en disco. Los dashboards marcaban verde porque monitorizaban
fechas de expiración leyendo archivos locales. Luego un día un certificado realmente expiró porque la ventana mensual se movió
por un evento de negocio, y nadie recargó.

Los demonios siguieron sirviendo el certificado antiguo, ahora expirado. Algunos clientes lo ignoraron temporalmente; otros se negaron de plano.
Las fallas de envío golpearon primero (587/465). Los usuarios podían recibir correo (las sesiones IMAP se mantuvieron), pero no podían enviar.
Ese es exactamente el modo de fallo que crea escaladas ejecutivas: “No puedo enviar correo a la junta.”

El postmortem fue incómodo: la “optimización” estaba pensada para evitar downtime, pero creó una caída diferida
que fue más difícil de detectar. Su monitorización comprobaba lo equivocado: el sistema de archivos, no la red.
Cambiaron la política a: renovación automática y recarga automática, condicionada por una prueba canaria de handshake.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día (staging, canarias y huellas)

Una compañía de pagos trataba el correo como un “mal necesario” pero lo gestionaba como producción de verdad. Tenían tres hábitos:
(1) siempre probar lo que se sirve externamente, (2) desplegar certificados mediante una copia controlada a un directorio propiedad del servicio,
y (3) recargar durante horas laborables con una comprobación canaria, porque es cuando los humanos están despiertos.

En un ciclo de renovación, su cliente ACME produjo un certificado válido, pero la cadena intermedia cambió (todavía válida, sólo distinta).
Un pequeño conjunto de escáneres muy antiguos en un almacén rechazó la nueva cadena. A nadie le importaban los escáneres—hasta que sí,
porque esos escáneres enviaban excepciones por correo.

La canaria lo detectó. Su suite de pruebas incluía un perfil de cliente “legacy conocido” que aún existía en producción.
La canaria no bloqueó el despliegue permanentemente; provocó una decisión: mantener la cadena moderna para los endpoints públicos,
y ejecutar un hostname interno dedicado con una cadena de compatibilidad para el segmento del almacén.

La práctica aburrida gana otra vez. No tuvieron una caída; tuvieron una corrección de compatibilidad controlada. Esa es la diferencia
entre “el día de renovación” y “martes”.

Listas de verificación / plan paso a paso para el día de renovación

Principios (la parte opinada)

  • Nunca despliegues un certificado que no hayas validado desde la red. Las comprobaciones en disco son necesarias, pero no suficientes.
  • Sirve una cadena completa. Usa fullchain.pem a menos que estés haciendo algo intencionalmente raro.
  • Automatiza recargas, pero conciéncialas. Un hook de recarga que ejecute una prueba de handshake antes y después no es “automatización peligrosa,” es más seguro que los humanos.
  • No “arregles” problemas de certificados debilitando TLS. No estás depurando, estás creando un incidente futuro.
  • Asume que tienes split‑brain hasta demostrar lo contrario. Mail multinodo + balanceadores + renovaciones = inconsistencia por defecto.

Plan paso a paso: pipeline de renovación seguro (nodo único)

  1. Renovar en una ubicación de staging.
    Mantén estable el directorio de certificados en vivo del servicio hasta que hayas verificado emparejamiento de clave y SANs.
  2. Validar emparejamiento de certificado y clave localmente (Tarea 2). Si hay desajuste, detente.
  3. Validar la estructura de la cadena (Tarea 14). Si sólo está la hoja, detente.
  4. Copiar archivos al directorio propiedad del servicio con permisos estables.
    Evita apuntar demonios directamente a directorios ACME si tu modelo de seguridad lo hace frágil.
  5. Recargar Dovecot y Postfix (Tarea 11).
  6. Ejecutar pruebas de handshake externas para 25/587/465/993 (Tareas 5–8). Confirma SANs y el código de verificación.
  7. Confirmar huellas para auditabilidad (Tarea 13). Regístralas en la nota de cambio.
  8. Vigilar logs y colas durante 15–30 minutos. El correo a veces falla lentamente.

Plan paso a paso: multinodo con balanceador

  1. Elegir un nodo canario. Drena el LB (o reduce peso) pero mantenlo accesible para pruebas.
  2. Desplegar certificado en el nodo canario (copia en staging), recarga servicios.
  3. Probar el canario directamente por IP/DNS usando SNI y el hostname esperado (Tareas 5–8 más Tarea 13).
  4. Reincorporar el canario al LB y monitorizar tasas de error y logs. Si está limpio, avanzar nodo a nodo.
  5. Después del despliegue, probar el VIP del LB y también cada backend para asegurar que las huellas coinciden (Tarea 13).

Ejemplo de hook de renovación: validar antes de recargar, validar después

Esto no es un “tutorial de scripts,” es un patrón: el evento de renovación dispara pruebas, luego recarga, luego re‑pruebas.
Las pruebas deben salir con status no‑cero si la verificación falla.

cr0x@server:~$ sudo bash -lc 'cat >/usr/local/sbin/mail-tls-postrenew.sh <<'"'"'EOF'"'"'
#!/usr/bin/env bash
set -euo pipefail

HOST="mail.example.com"

precheck() {
  echo | openssl s_client -starttls smtp -connect 127.0.0.1:587 -servername "$HOST" 2>/dev/null \
    | openssl x509 -noout -enddate >/dev/null
}

postcheck() {
  echo | openssl s_client -starttls smtp -connect "$HOST:587" -servername "$HOST" -verify_return_error 2>/dev/null \
    | openssl x509 -noout -enddate
  echo | openssl s_client -connect "$HOST:993" -servername "$HOST" -verify_return_error 2>/dev/null \
    | openssl x509 -noout -enddate
}

precheck
systemctl reload postfix
systemctl reload dovecot
postcheck
EOF
chmod 0755 /usr/local/sbin/mail-tls-postrenew.sh
/usr/local/sbin/mail-tls-postrenew.sh'
notAfter=Apr  1 00:12:02 2026 GMT
notAfter=Apr  1 00:12:02 2026 GMT

Significado: Las comprobaciones antes y después tuvieron éxito; la recarga no rompió la verificación externa.

Decisión: Si este script falla, trátalo como un despliegue fallido: revierte o detén el rollout. No sigas haciendo recargas en bucle.

Errores comunes: síntomas → causa raíz → solución

Estos no son teóricos. Son los que aparecen a las 02:00 con un on-call muy despierto.

1) “Se renovó, pero los clientes siguen viendo el certificado antiguo”

Síntomas: En disco el certificado es nuevo; externamente la huella del certificado no cambió.
Los clientes siguen avisando de expiración o certificado no confiable.

Causa raíz: El servicio no se recargó, o el servicio apunta a rutas de archivo diferentes a las que actualizaste.
En clusters, un nodo no recibió la actualización.

Solución: Verifica el certificado servido con la Tarea 13. Recarga demonios (Tarea 11). Confirma rutas de configuración (Tareas 3–4).
Para multinodo: comprueba la huella de cada nodo y arregla la inconsistencia de despliegue.

2) “Fallo de handshake: key values mismatch / clave equivocada”

Síntomas: Logs de Postfix/Dovecot muestran desajuste de clave; TLS no inicializa; el servicio puede negarse a iniciar TLS.

Causa raíz: Certificado y clave privada no coinciden, normalmente por copiar sólo algunos archivos, mezclar ECDSA y RSA,
o apuntar al privkey.pem equivocado.

Solución: Ejecuta la comprobación de módulo (Tarea 2). Corrige rutas de archivos y despliega el par correcto.
Si rotas claves, rota ambos a la vez, de forma atómica.

3) “Algunos clientes funcionan, otros no (especialmente Outlook o dispositivos embebidos)”

Síntomas: Clientes modernos conectan bien; dispositivos antiguos fallan con “no confiable” o “no se puede verificar.”

Causa raíz: Serviste sólo la hoja (sin intermediario) o serviste una cadena que esos clientes no pueden reconstruir.

Solución: Sirve fullchain.pem (Tareas 3–4, 14). Si verdaderamente tienes dependencias legacy,
puede que necesites una estrategia de cadena de compatibilidad (pero no la copies sin pruebas: prueba con los dispositivos reales).

4) “Desajuste de nombre de host después de la renovación”

Síntomas: Error como “certificate subject name does not match target host name.”
Ocurre en algunos puertos/nombres pero no en otros.

Causa raíz: Entradas SAN faltantes, hostname incorrecto usado por clientes, o configuración vhost distinta por puerto.
A veces el enrutamiento SNI está mal (LB envía el certificado equivocado para el nombre).

Solución: Inspecciona SANs (Tarea 1). Valida con SNI usando -servername (Tareas 5–8).
Corrige la emisión del certificado para incluir todos los hostnames usados y alinea DNS/clientes si hay deriva.

5) “Sólo ciertos dominios externos rebotan correo con TLS requerido”

Síntomas: El correo a la mayoría de dominios funciona. Algunos dominios devuelven rebotes como “TLS requerido pero handshake falló.”

Causa raíz: Aplicación de políticas vía MTA-STS o DANE por parte del receptor; tu oferta TLS o validación falla bajo reglas estrictas.

Solución: Reproduce con verificación estricta (Tarea 5 con -verify_return_error).
Asegura cadena correcta, nombre correcto y versiones de protocolo sensatas. No desactives TLS; arregla el cumplimiento.

6) “La recarga funcionó, y horas después empezaron quejas IMAP”

Síntomas: Fallas de evolución lenta, especialmente en IMAP; no atadas al momento de la recarga.

Causa raíz: Tormentas de reconexión de clientes revelan problemas de certificado o cadena gradualmente; algunos clientes cachéaban intermediarios y luego pierden la caché.

Solución: Valida IMAPS externamente (Tarea 8) y confirma la cadena completa.
Monitoriza logs por alertas TLS tras la renovación. Considera forzar una ventana de reconexión controlada si necesitas limpiar sesiones antiguas.

Monitorización y alertas que detectan esto antes que los usuarios

El error habitual en monitorización es comprobar la fecha de expiración en el sistema de archivos. Eso te dice qué está disponible,
no qué está servido. Monitoriza desde la red, por puerto, por hostname, desde al menos dos ubicaciones.

Qué monitorizar (mínimo viable)

  • Expiración del certificado servido en 25 (STARTTLS), 587 (STARTTLS), 465 (implícito), 993 (implícito), y cualquier puerto POP que expongas.
  • Tasa de éxito de handshake (binaria). O puedes establecer TLS y verificar la cadena, o no.
  • Deriva de huellas de certificado entre nodos y el VIP (opcional, pero oro para diagnosticar split‑brain).
  • Profundidad de cola y tasa de defer para Postfix. Los fallos de cert suelen mostrarse como diferidos y reintentos.
  • Tasa de errores TLS en logs para Postfix y Dovecot.

Ejemplo: comprobación rápida de expiración desde la red (cron‑friendly)

cr0x@server:~$ bash -lc 'host=mail.example.com
for p in 465 993; do
  echo -n "$host:$p "
  echo | openssl s_client -connect $host:$p -servername $host 2>/dev/null | openssl x509 -noout -enddate
done'
mail.example.com:465 notAfter=Apr  1 00:12:02 2026 GMT
mail.example.com:993 notAfter=Apr  1 00:12:02 2026 GMT

Significado: La expiración del certificado servido es visible y consistente en puertos TLS implícitos.

Decisión: Alertar si la expiración está dentro de tu umbral (por ejemplo, 14 días) o si el comando falla (la falta de salida suele significar fallo de handshake).

Señal basada en logs: encontrar fallos TLS rápido

cr0x@server:~$ sudo journalctl -u postfix -S "1 hour ago" --no-pager | egrep -i 'tls|handshake|SSL|certificate|verify|alert' | tail -n 20
Jan 04 11:02:07 mail postfix/smtpd[22911]: warning: TLS library problem: error:0A000086:SSL routines::certificate verify failed
Jan 04 11:02:07 mail postfix/smtpd[22911]: warning: TLS library problem: error:0A000418:SSL routines::tlsv1 alert unknown ca

Significado: Hay errores TLS activos. “unknown ca” suele indicar un problema de cadena o de confianza del cliente.

Decisión: Si esto se dispara tras la renovación, trátalo como una regresión; confirma que estás sirviendo la cadena completa y no un certificado inesperado.

Broma #2: Lo único que se renueva más rápido que un certificado Let’s Encrypt es un rumor de caída de correo en el chat corporativo.

Endurecimiento: cadenas, cifrados, SNI, DANE, MTA-STS y la realidad

Usa fullchain por defecto, pero entiende qué es

fullchain.pem es tu certificado hoja más los intermediarios necesarios para llegar a una raíz de confianza.
La mayoría de los clientes no quieren ir a buscar intermediarios en mitad del handshake.

Tu demonio de correo típicamente debería presentar:

  • Certificado hoja (para mail.example.com)
  • Certificado(s) CA intermedio(s)
  • No el certificado raíz CA (los clientes ya tienen raíces; incluirla puede confundir a algunas pilas)

SNI: la trampa silenciosa en configuraciones multi‑dominio

Si sirves múltiples dominios/certificados en una IP, los clientes que usan SNI solicitarán el nombre correcto.
Algunos clientes SMTP lo hacen, otros no, y algunos proxies lo eliminan.
Los balanceadores de carga pueden terminar TLS y volver a cifrar, cambiando lo que el cliente ve.

Consejos operativos:

  • Prueba siempre con -servername (Tareas 5–8). Eso aproxima el comportamiento real del cliente.
  • También prueba sin SNI de vez en cuando. Si tu certificado “por defecto” es incorrecto, los clientes legacy pueden recibirlo.

Versiones de protocolo y suites de cifrado: sé estricto, pero no performativo

Para correo, TLS 1.2 como mínimo es una base sensata. TLS 1.3 es excelente, pero no necesitas tratarlo como una declaración de identidad.
La trampa mayor es endurecer demasiado rápido sin inventariar clientes legacy.

Si quieres saber qué estás ofreciendo, compruébalo directamente:

cr0x@server:~$ openssl s_client -connect mail.example.com:993 -servername mail.example.com -tls1_2 </dev/null | egrep 'Protocol|Cipher|Verify return code'
Protocol  : TLSv1.2
Cipher    : ECDHE-RSA-AES256-GCM-SHA384
Verify return code: 0 (ok)

Significado: TLS 1.2 funciona y la verificación pasa.

Decisión: Si TLS 1.2 falla pero TLS 1.3 funciona, puede que hayas hecho el servidor demasiado estricto para algunos clientes. Decide si eso es aceptable; si no, amplía la compatibilidad de forma intencional.

DANE: potente, pero te obliga a ser correcto

DANE para SMTP usa registros TLSA firmados por DNSSEC para decir a los remitentes qué certificado/clave esperar.
Eso es genial para seguridad y terrible para renovaciones descuidadas.

Si usas DANE, cualquier cambio de clave requiere actualizaciones TLSA. Si fijas la SPKI de la hoja y rotas claves sin actualizar DNS,
remitentes estrictos te tratarán como hostil.

MTA-STS: la política convierte tu “casi funciona” en inaceptable

MTA-STS no hace perfecto al TLS, pero hace la falla accionable: si anuncias una política que diga “enforce”,
los receptores empezarán a exigir un handshake válido al hostname correcto.

Eso significa que los errores de renovación pasan de “algunos clientes avisan” a “correo rebotado.”
Si habilitas MTA-STS, implícitamente aceptas ser disciplinado con los certificados.
Está bien. Sólo no lo hagas a medias.

Atomicidad: desplegar como una unidad, no como archivos individuales

El certificado, la clave y la cadena son una unidad. No los copies uno a uno mientras el servicio se recarga.
Si tienes que copiar, copia a un directorio nuevo y cambia un symlink de forma atómica, luego recarga.

Esto es especialmente importante en servidores con mucho tráfico donde una recarga puede ocurrir a mitad de la copia, produciendo fallos intermitentes que
desaparecen cuando “lo intentas de nuevo.” Esos son los peores incidentes: los que hacen gaslighting al on‑call.

Preguntas frecuentes

1) ¿Necesito reiniciar Postfix/Dovecot para recoger un certificado renovado?

Normalmente un systemctl reload es suficiente, pero sólo si el demonio vuelve a leer el certificado al recargar.
Confirma comprobando la huella servida (Tarea 13). Si no cambió, necesitas un reinicio o tu recarga no está cableada.

2) ¿Debo apuntar las configuraciones a cert.pem o a fullchain.pem?

Usa fullchain.pem para servicios de correo a menos que tengas una razón probada para no hacerlo. Sólo la hoja a menudo rompe clientes antiguos o más estrictos.

3) ¿Por qué funciona el puerto 25 pero falla el 587 (o viceversa)?

Diferentes listeners, diferentes bloques de configuración, diferentes procesos, o distintos puntos de terminación (LB/proxy).
Trata cada puerto como su propio producto y pruébalo explícitamente (Tareas 5–7).

4) ¿Cómo sé qué certificado ven realmente los clientes?

Usa openssl s_client desde fuera de tu red y registra la huella (Tarea 13). No confíes en los archivos locales.

5) ¿Cuál es la forma más rápida de detectar split‑brain entre nodos de correo?

Compara huellas por nodo y en el VIP. Si dos nodos presentan certificados distintos, tu despliegue no es consistente.
Las huellas lo hacen obvio en segundos.

6) ¿Puedo evitar recargas confiando en la recarga en caliente de archivos?

Algún software puede vigilar archivos; muchas pilas de correo no lo hacen de forma fiable, y el comportamiento varía por versión y parches de distro.
Asume que necesitas una recarga explícita y diseña la automatización en torno a eso.

7) ¿Y los certificados ECDSA—son seguros para clientes de correo?

A menudo sí, pero no universalmente. Algunos clientes y appliances legacy tienen soporte ECDSA incompleto.
Si tu base de usuarios incluye dispositivos antiguos, considera certificados duales o prueba antes de cambiar de algoritmo.

8) ¿Qué pasa si uso un balanceador de carga que termina TLS?

Entonces la renovación es un problema del LB primero: actualiza el almacén de certificados del LB y valida en el VIP.
También asegúrate de que el TLS backend (si lo usas) sea correcto, pero recuerda que el cliente ve el certificado del LB.

9) ¿Por qué los problemas IMAP aparecen más tarde que los de SMTP?

Los clientes IMAP suelen mantener sesiones TLS de larga duración (especialmente con IDLE). Los clientes de submission se reconectan con frecuencia.
Así que submission falla ruidosa y rápidamente; IMAP puede fallar lentamente a medida que las sesiones churn.

10) ¿Está bien deshabilitar temporalmente la verificación de certificados para “hacer que el correo fluya”?

Para aplicaciones cliente, no. Para servidor a servidor, debilitar la verificación probablemente tampoco ayude porque los pares aplican políticas.
Además estarás entrenando a tu organización a aceptar soluciones inseguras. Arregla el certificado y la cadena correctamente.

Próximos pasos (de los prácticos)

Si quieres que el día de renovación parezca un no‑evento, haz lo siguiente:

  1. Añadir comprobaciones de certificado basadas en red para 25/587/465/993, por hostname, y alertar tanto por expiración como por fallo de handshake.
  2. Estandarizar el despliegue con cadena completa y verificar cobertura SAN antes de recargar.
  3. Implementar un hook post‑renew con puerta que ejecute pruebas de handshake, recargue servicios y re‑pruebe (patrón mostrado arriba).
  4. Hacer el rollout atómico y consistente entre nodos: copia en staging, swap de symlink, luego recarga, luego verificación de huellas.
  5. Escribir tus pasos de “diagnóstico rápido” en el runbook on‑call e incluir los comandos exactos que ejecutarás a las 02:00.

El objetivo no es hacer las renovaciones TLS emocionantes. El objetivo es hacerlas aburridas—y aburrido es el mayor cumplido que pueden ganar los sistemas en producción.

← Anterior
Debian 13: Fugas de memoria en servicios — localízalas con la menor interrupción (caso #43)
Siguiente →
DNS inverso (PTR): por qué tu correo sufre y cómo arreglar rDNS correctamente

Deja un comentario