Discourse + Let's Encrypt con múltiples nombres de host

Al migrar (mediante una copia de seguridad) un Discourse de un nombre de host a otro, un administrador podría querer mantener el nombre de host antiguo pero configurar el servidor web para que reescriba las solicitudes y utilice el nombre canónico nuevo, por ejemplo:

https://old.example.org/t/my-great-topic/12345 :arrow_heading_down:
https://new.example.org/t/my-great-topic/12345

Desafortunadamente, esto no es tan sencillo como cambiar simplemente el registro CNAME o A en el DNS; el cliente del navegador generará un error o advertencia porque el nombre de host no coincide con el certificado generado por la instalación de Discourse a través de Let’s Encrypt.

En una instalación manual de un servidor web, usaría la utilidad certbot para generar un certificado con múltiples nombres asignados a él. Sin embargo, la configuración de Discourse pasa únicamente el nombre de host de Discourse a Let’s Encrypt, y no veo ningún concepto en la configuración de Discourse para alias.

¿Alguien ha configurado una disposición así, o tiene alguna idea sobre la mejor manera de lograrlo? Imagino que implicará alguna modificación de las plantillas de SSL y Let’s Encrypt.

No es específico de Discourse, pero cuando necesito redirigir mediante HTTPS, simplemente redirijo todo. Es decir, tener un servidor que realice la redirección desde la dirección antigua a la nueva. Algunas opciones de alojamiento se encargan de esto en segundo plano; a veces se le llama servicio de “redirección de dominio” o “reenvío”.

Ni siquiera lo pienso más, porque cada vez que he intentado algo más ha sido un dolor de cabeza. :thinking:

Discourse solo responderá a un nombre de host. Si necesitas más de un nombre de host —y tu caso de uso, que consiste en dar soporte al nombre de host anterior, es el más común— entonces deberás redirigir uno al otro.

Recomiendo hacerlo fuera de Discourse. Simplemente crea una configuración de nginx que tenga su propio certificado, tenga un server_name para el nombre de host antiguo y redirija todo al nuevo nombre de host.

En realidad, si estás utilizando una instalación basada en Docker con una sola instancia por servidor, responderá correctamente a cualquier número de entradas DNS (nginx escucha en los puertos 80 y 443 para todos los nombres de host) y reescribirá la URL correctamente al nombre de host “nuevo” canónico. Esa parte funciona bien y sin problemas. (Las personas que estén inclinadas a probar esto pueden hacerlo agregando un nombre de dominio ficticio al archivo localhost de su máquina y apuntándolo a una dirección IP de su sitio de Discourse favorito.)

El único problema que estoy encontrando es la advertencia de SSL, porque la respuesta de reescritura de nginx es desde https://old.example.org/foo y envía una redirección HTTP 302 a la nueva URL.

Preferiría no tener que mantener un servidor web separado solo para hacer una regla de reescritura, si es posible. :slight_smile:

No es necesario; solo necesitas una sección server adicional en tu configuración.

Tal vez puedas echar un vistazo a Set up Let’s Encrypt with multiple domains / redirects

Actualización: Configuración exitosa del nombre de dominio secundario en la instalación independiente y emisión de un certificado de Let’s Encrypt para gestionar tanto los nombres antiguos como los nuevos.

Precondición: Aún no he cambiado los registros DNS para redirigir a los usuarios al nuevo sitio; quería asegurarme de que todo funcionara antes. Por lo tanto, estaba utilizando una entrada de localhost en mi máquina de pruebas. Esto significa que no pude realizar una verificación normal de Let’s Encrypt y, en su lugar, tuve que usar el método “DNS” de acme.sh, que generalmente no se recomienda porque no permite la renovación automática. Esto no es un problema para mí, ya que cambiaré dentro del plazo de 30 días del certificado “inicial” (emitido recientemente con dos nombres).

  1. En mi archivo web_only.yml (es posible que estés usando app.yml), bajo la sección hooks: y antes de los plugins, agregué lo siguiente:
  after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d second-domain.com --keylength"
  1. En DNS, configura un registro TXT falso/temporal para _acme-challenge.old.example.org con un TTL de 5 minutos (podrías configurarlo más corto) y espera a que se propague para realizar rápidamente el cambio con la clave de verificación de acme.sh (Let’s Encrypt).

  2. Detén el sitio y realiza una validación de depuración (prueba) para que el sistema reconozca el TTL corto de la nueva entrada:

./launcher enter app
sv stop nginx
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf
LE_WORKING_DIR=/shared/letsencrypt DEBUG=1 /shared/letsencrypt/acme.sh --issue -d new.example.org -d old.example.org -k 4096 -w /var/www/discourse/public --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please --force
  1. Ejecuta la solicitud de verdad esta vez sin la configuración de depuración. Esto te mostrará una advertencia con el valor que debes usar en DNS para la entrada que creaste en el paso 2:
LE_WORKING_DIR=/shared/letsencrypt /shared/letsencrypt/acme.sh --issue -d new.example.org -d old.example.org -k 4096 -w /var/www/discourse/public --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please --force
  1. Actualiza los registros DNS y luego espera 5 minutos. Sí, debes esperar todo el tiempo para no toparte con las limitaciones de Let’s Encrypt.

  2. Ejecuta una versión similar al último comando pero en modo renew (renovación):

LE_WORKING_DIR=/shared/letsencrypt /shared/letsencrypt/acme.sh --issue -d new.example.org -d old.example.org -k 4096 -w /var/www/discourse/public --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please --force --renew
  1. Deberías recibir una confirmación. Ejecuta lo siguiente para limpiar y colocar el nuevo certificado:
LE_WORKING_DIR=/shared/letsencrypt /shared/letsencrypt/acme.sh --installcert -d new.example.org -d old.example.org --fullchainpath /shared/ssl/new.example.org.cer --keypath /shared/ssl/new.example.org.key --reloadcmd "sv reload nginx"
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop
exit
  1. Último paso ahora que has salido del launcher:
rm -rf /var/discourse/shared/standalone/ssl
rm -rf /var/discourse/shared/standalone/letsencrypt
./launcher rebuild app

Una vez que el sitio esté de nuevo en línea, debería estar funcionando con el nuevo certificado. Es posible que tengas que borrar los certificados almacenados en tu navegador, lo cual se deja como ejercicio para el lector y tu motor de búsqueda favorito.

¡Gracias a quienes me indicaron el camino correcto!

Esta es una aplicación perfecta para una regla de Cloudflare: cero configuración del servidor. Simplemente envía los mismos parámetros de URL al nuevo dominio.

La nube naranja deberá estar habilitada para el nombre de dominio antiguo.

Sí, una situación de proxy inverso como la de Cloudflare (o supongo que tu propio proxy inverso de elección frente a tu sitio de Discourse) podría solventarlo implementando las reglas de reescritura “un nivel arriba”. En este caso, Cloudflare no era una opción por razones de seguridad y éticas. :slight_smile:

(Véase arriba para la solución independiente.)