Let's Encrypt renovaciones de certificados (de repente) fallando

Hace algún tiempo — no está claro cuánto tiempo, pero al menos varios meses — las renovaciones de Let’s Encrypt comenzaron a fallar en mi foro de Discourse, después de funcionar bien durante años. Cuando noté esto por primera vez hace unos días, el certificado había expirado en agosto de 2021. Después de intentar algunas renovaciones manuales y reinicios de nginx, encontré que el certificado se actualizó para expirar hace solo unos días. Todavía no es un certificado actual, obviamente. Ejecutar manualmente acme.sh para forzar una renovación (dentro del contenedor de Discourse) está produciendo este error (donde [site] es la dirección de mi sitio, por supuesto):

[site]:Verify error:Fetching http://[site]/.well-known/acme-challenge/[long alpha challenge string]: Error getting validation data

Debo señalar que el sitio requiere inicio de sesión para todo el acceso de los usuarios, pero esto no ha sido un problema para las renovaciones de certificados SSL durante los años de operación anterior.

¿Alguna idea? ¡Muchas gracias!

ACTUALIZACIÓN: Probar la verificación usando wget devuelve un 404. Sin embargo, no sé dónde se configura esta información en nginx para Discourse en un contenedor y cómo se relaciona con el nginx relacionado que actúa como proxy fuera del contenedor.

2 Me gusta

Si es de hace unos meses, ¿tiene algo que ver con esto?:

2 Me gusta

Hola. Eso no debería estar relacionado, porque ese problema haría que los certificados fueran rechazados por el navegador con errores diferentes, no errores de caducidad como en mi caso. Parece que Let’s Encrypt de repente no puede autenticarse con Discourse para entregar nuevos certificados. Gracias.

2 Me gusta

No, si la primera caducidad fue en agosto. Debería haberse renovado después de eso.

4 Me gusta

Para una aplicación no actualizada después de junio, podría haber ocurrido este problema: Letsencrypt certificate failure to renew - #11 by pfaffman

no estoy seguro si es lo que buscas, pero: discourse_docker/templates/web.letsencrypt.ssl.template.yml at main · discourse/discourse_docker · GitHub

2 Me gusta

Hola. Estos no parecen aplicarse. Estoy viendo un error 404, no los otros errores, las compilaciones se han actualizado todo el tiempo y esa plantilla de GitHub es, de hecho, la versión que ya está instalada en mi instalación. ¡Gracias!

3 Me gusta

¿Estás usando Cloudflare con la nube naranja o algún otro proxy inverso?

2 Me gusta

Negativo. Alojado localmente en Ubuntu 18.04 usando la instalación predeterminada de Docker.

3 Me gusta

La ejecución manual del cron job (en contenedor) para la renovación de certificados siempre falla de la misma manera. El intento de obtener:

http://[site]/.well-known/acme-challenge/[challenge-string]

falla con “Error al obtener datos de validación”.

2 Me gusta

Al no estar familiarizado con el proceso, ¿podría estar esperando que el contenedor esté en un estado que no es el caso cuando se ejecuta ese script solo? Por ejemplo, ¿quizás está esperando que ocurra otro trabajo cron primero que prepare nginx para permitir el acceso a dicha URL?

¿Has intentado reconstruir? (Lo que intentará obtener un nuevo certificado en el proceso).

Mencionas que está alojado localmente. ¿Puedes acceder a la instancia desde fuera de tu red usando el nombre de dominio?

2 Me gusta

Hola, sí, múltiples reconstrucciones. Sin cambios. Uso Let’s Encrypt en varios sitios que no son de Discourse y todos se renuevan sin problemas. Sí, puedo acceder desde un sitio externo y he probado usando wget, el resultado es 404. Pregunta: Exactamente ¿dónde vive el árbol html de nginx en este caso, la parte que contendría (o debería contener) el directorio .well-known? No he podido encontrarlo. Gracias.

2 Me gusta

No encontré un cron job, solo un script de runlevel en /etc/runit/1.d/letsencrypt. Parece que ese script inicia una nueva instancia de nginx con una configuración que incluye esto:

location ~ /.well-known {
  root /var/www/discourse/public;
  allow all;
}

Creo que eso significa que la ruta terminaría siendo /var/www/discourse/public/acme-challenge, aunque es posible que se cree antes del desafío y luego se elimine.

Si ese es el script que intentaste ejecutar manualmente, ¿detuviste nginx primero? La instancia que el script intenta iniciar intentará escuchar en el puerto 80, así que sospecho que fallaría si nginx ya se está ejecutando para Discourse.

2 Me gusta

Creo que puedo ver el problema. Pero no sé cómo solucionarlo. Parece que todos los intentos de acceder al foro en el puerto https 80 están siendo (como se esperaba) redirigidos a https 443. Correcto. Pero esto significa que cuando Let’s Encrypt intenta validar para la renovación, falla, porque el certificado actual ha expirado. Puedo ver la redirección con wget. Entonces, la pregunta es, ¿cómo desactivo temporalmente la redirección para que Let’s Encrypt pueda validar y obtener un nuevo certificado no caducado? Una posible complicación adicional es que la redirección es un 301 permanente. Gracias.

2 Me gusta

Esta redirección está en /etc/nginx/conf.d/discourse.conf y no se utilizará cuando nginx se detenga y luego se inicie con la configuración mencionada en mi publicación anterior.

Me temo que no estoy muy familiarizado con cómo funciona la actualización automática, por lo que no estoy seguro de cuál sería el método apropiado para renovar mientras el contenedor se está ejecutando. En teoría, simplemente detener e iniciar el contenedor debería resultar en su renovación, pero dado que dijiste que una reconstrucción no lo hizo, eso probablemente tampoco lo hará.

acme.sh tiene opciones como --renew-all, pero no estoy seguro de qué otras opciones se necesitan para que haga lo correcto aquí. Lo siguiente podría ser todo lo que necesitas, pero no puedo decirlo con certeza.

LE_WORKING_DIR="/shared/letsencrypt" /root/acme.sh/acme.sh --renew-all
2 Me gusta

Y, de hecho, esto permite que Let’s Encrypt acceda sin la redirección, pero aparentemente el archivo que está buscando no existe, por lo que, en última instancia, se produce el mismo error de verificación.

2 Me gusta

Tengo el mismo problema. ¿Alguien ha encontrado un procedimiento claro para corregir el problema?

2 Me gusta

Ahora estoy usando esto para intentar obtener el certificado con éxito. Parece que el token de validación SÍ está siendo recuperado por curl, ¡pero acme.sh SIGUE declarando un fallo de validación cada vez! Así que sigo sin servicio.

«/shared/letsencrypt»/acme.sh --renew-all --force --insecure --home «/shared/letsencrypt» --debug

2 Me gusta

Hola @L30110 :slightly_smiling_face:

Soy uno de los habituales en la comunidad de Let’s Encrypt. @JimPas me envió para echar un vistazo a este hilo, lo cual haré tan pronto como regrese de almorzar.

3 Me gusta

Con muchos clientes ACME (como acme.sh) cuando nginx se especifica como método de autenticación, el archivo del reto http-01 se crea en un directorio específico basado en una excepción/redirección en la configuración del servidor nginx en lugar de directamente en la estructura de directorios .well-known/acme-challenge en el directorio webroot. A menudo, esta redirección solo existe temporalmente durante la verificación del reto, al igual que los propios archivos del reto.

Por lo tanto:


Una consideración sabia. Un script de renovación bien escrito debería hacer innecesario detener nginx. Típicamente, nginx se usa para servir los archivos del reto y luego se usa algo parecido a nginx -s reload para recargar elegantemente el servidor web/proxy una vez que se adquiere el nuevo certificado.


No. :wink:

Según Challenge Types - Let's Encrypt

Nuestra implementación del reto HTTP-01 sigue las redirecciones, hasta 10 redirecciones de profundidad. Solo acepta redirecciones a “http:” o “https:”, y solo a los puertos 80 o 443. No acepta redirecciones a direcciones IP. Cuando se redirige a una URL HTTPS, no valida los certificados (ya que este reto está destinado a iniciar certificados válidos, puede encontrar certificados autofirmados o caducados en el camino).


Típicamente, cuando vemos problemas como este, uno de los siguientes suele ser el culpable:

  • Un firewall no permite el tráfico al servidor web/proxy que está sirviendo los archivos del reto.
  • Un enrutador/proxy está mapeado/configurado incorrectamente de tal manera que la solicitud de verificación del reto de Boulder (el servidor CA de Let’s Encrypt) intenta recuperar los archivos de un servidor web o directorio incorrecto.
  • Algún tipo de reescritura/redirección (por ejemplo, archivos .htaccess en Apache) está interfiriendo con la capacidad del servidor web/proxy para servir los archivos del reto desde la ubicación correcta.
  • Uso de puertos no estándar, generalmente con mapeo incorrecto.
  • El contenedor que ejecuta el cliente ACME está creando los archivos del reto en un lugar donde el servidor web/proxy (por ejemplo, nginx) no los sirve. Cuando Docker está involucrado, este es casi siempre el problema.
2 Me gusta

Hola. Entonces, de esos diversos elementos que enumeraste, varios claramente no se aplican en mi caso. No es un problema de firewall: puedo acceder manualmente al token con wget o curl desde 1) dentro de la aplicación Docker de Discourse, 2) desde fuera del contenedor Docker en el sistema host y 3) un sistema relacionado.

Para estos casos manuales, SÍ obtengo el contenido del token de la ubicación esperada, asumiendo que se especifica --ignore o -k para pasar el certificado caducado cuando Discourse redirige a https automáticamente.

No he cambiado ningún aspecto de la configuración de nginx creada por Discourse, ni dentro ni fuera del contenedor Docker de Discourse. No ejecuto ninguna copia de nginx, y Apache vive en puertos completamente diferentes solo para uso local. Teniendo en cuenta que todo esto había estado funcionando bien durante más de dos años, con renovaciones de certificados de rutina y sin otros cambios en la aplicación, es una máquina muy estable.

Sin puertos inusuales.

Dado que puedo obtener el contenido del token manualmente, no veo cómo podrían estar involucradas ubicaciones incorrectas. EXCEPTO…

No estaba deteniendo nginx manualmente para mis pruebas. Ahora lo he hecho y no hubo una diferencia significativa: los mismos errores de acme.sh (actualmente error 56 nuevamente). Cuando nginx se detiene desde dentro del contenedor, veo una instancia de runsv nginx en el host, pero no tiene procesos de trabajador o caché. Cuando reinicio nginx en el contenedor, los procesos de trabajador y caché reaparecen en el host junto con el runsv nginx que había permanecido. Los comandos sv start/stop nginx dentro del contenedor dan las confirmaciones esperadas de esas acciones.

Pero hay algo más mencionado anteriormente que puede ser motivo de preocupación. Y no entiendo por qué esto sería un problema de repente, dado cuánto tiempo funcionaron las cosas hasta ahora.

La dirección IP estática del foro que se utiliza desde fuera de mis redes locales no es utilizable por esa máquina para conectarse a los propios servicios de esa máquina, debido a las complejidades de la forma en que el ISP proporciona las direcciones IP estáticas. Rutinariamente he utilizado entradas en /etc/hosts para proporcionar direcciones IP de red local para esos nombres. Por lo tanto, cuando pruebo con curl en la misma máquina (dentro o fuera del contenedor, ambos tienen la adición de /etc/hosts para el foro), la prueba utiliza una dirección IP diferente (y local) que la que utilizaría un sitio externo al buscarla a través de DNS. ¿Hay alguna forma de que esto pueda ser relevante? Gracias.

2 Me gusta