Configurar Let's Encrypt con múltiples dominios / redireccionamientos

NOTE: @pfaffman says: This page needs to be cleaned up. There is now a new ENV setting that will let you add more hostnames. In your app.yml under your DISCOURSE_HOSTNAME line (it can go many places but that one makes sense), add

 DISCOURSE_HOSTNAME_ALIASES: domain.com,other.domain.com

and early reports suggest that you’ll get valid certs for those domains and that accessing https://domain.com will properly redirect you to your DISCOURSE_HOSTNAME without a certificate error.

If you do that and it works for you, you might add another “me too!” post to the bottom. If you feel comfortable, you could also edit this first post with the instructions that you think would be most helpful.


This is to address the problem where you get certificate errors with any redirects or CNAME DNS entries which point to your actual installed Discourse (sub)domain.

If you do not have https configured already (you do if you have done a standard install recently) see Setting up Let’s Encrypt as your first step.

Legacy Method

The method below no longer reliably works as of August 2025

There are three patterns that need to be replaced. Enter your (sub)domain (and any additional subdomains preceded by -d ) and then add the following to your app.yml hooks section (towards the end of the file):

2025-04-23 @pfaffman changed the code because there’s a 3rd place it needs to be changed

  after_ssl:
    - replace:
        filename: /etc/runit/1.d/letsencrypt
        from: /-d =domain1= /
        to: "-d =domain1= -d =domain2= "
        global: true

This will allow you to have HTTPS configured for a second domain that will redirect to the correct one without certificate issues.

If you need to add multiple extra domains, you can enter something like this in the domain2 field: www.bananas.com -d forum.bananas.com

For example, if you want people who visit https://forum.example.com to be redirected to your forum at https://community.example.com without a certificate error, this is all you need.

47 Me gusta

Gracias, ¿esto sirve para redirigir "www.example.com" a "comunnity.example.com"?
¿O cómo puedo hacerlo?
Tengo problemas con mi dominio www.example.com, he configurado DNS para redirigir a comunnity.example.com pero no funciona en Firefox ni en Chrome.

2 Me gusta

Hay una herramienta de verificación de redirecciones para comprobar tus redirecciones.

5 Me gusta

Me está costando un poco. Bueno, bastante.

Decidí experimentar añadiendo una CDN a uno de mis sitios.

Después de leer la documentación, me di cuenta de que era mejor para mi sitio mudarme a un subdominio desde su dominio raíz actual para cumplir con los criterios recomendados por Fastly (y el consejo general de hacerlo).

Así que pensé: “bah, esto será pan comido, ya lo he hecho antes…”. ¿Ah, sí? :sweat_smile:

El sitio en cuestión es https://starzen.space.

Lo mudé este fin de semana a https://www.starzen.space usando la guía de aquí: https://github.com/discourse/discourse/blob/main/docs/ANOTHER-INSTALL.md#moving-your-site-to-a-new-domain-or-subdomain

Todo fue bien, PERO, por supuesto, todavía necesito considerar la pequeña cantidad de usuarios que he captado hasta ahora en este sitio, así que quería añadir una redirección.

Tengo entendido que también necesito el enlace original emitido con un certificado, así que siguiendo esta guía (¿que antes era mucho más complicada?), añadí esto a app.yml:

hooks:
  after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d starzen.space --keylength"
    - replace:
        filename: "/etc/nginx/conf.d/discourse.conf"
        from: /return 301 https.+/
        to: |
          return 301 https://$host$request_uri;
  after_web_config:
    - replace:
        filename: /etc/nginx/nginx.conf
        from: /sendfile.+on;/
        to: |
          server_names_hash_bucket_size 64;
          sendfile on;
    - file:
        path: /etc/nginx/conf.d/discourse_redirect_1.conf
        contents: |
          server {
            listen 80;
            listen 443 ssl;
            server_name starzen.space;
            return 301 $scheme://www.starzen.space$request_uri;
          }

En una reconstrucción, todo parece ir bien.

Sin embargo, si intento acceder a https://starzen.space a través de un navegador, obtengo:

Y si hago curl:

blah discourse % curl https://starzen.space
curl: (60) SSL: no alternative certificate subject name matches target host name 'starzen.space'
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

Estoy bastante seguro de que el certificado es el culpable, porque si ejecuto lo mismo en modo inseguro obtengo:

blah discourse % curl -k https://starzen.space

301 Moved Permanently
301 Moved Permanently
nginx/1.21.6

que creo que es lo que quiero.

Creo que el script modificado es correcto, esto es lo que tengo:

root@starship-enterprise:/etc/runit/1.d# cat letsencrypt 
#!/bin/bash
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf

issue_cert() {
  LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh --issue $2 -d www.starzen.space -d starzen.space --keylength $1 -w /var/www/discourse/public
}

cert_exists() {
  [[ "$(cd /shared/letsencrypt/www.starzen.space$1 && openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer | grep "OK")" ]]
}

########################################################
# RSA cert
########################################################
issue_cert "4096"

if ! cert_exists ""; then
  # Try to issue the cert again if something goes wrong
  issue_cert "4096" "--force"
fi

<SNIP>

Incluso he ejecutado esto desde la línea de comandos dentro del contenedor, antes de lo cual he movido TODOS los archivos de certificado del directorio de destino a un directorio de copia de seguridad para que se ejecute el comando correcto para el dominio doble:

root@starship-enterprise:/etc/runit/1.d# ./letsencrypt 
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()
[Sun 25 Sep 2022 05:50:04 PM UTC] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Sun 25 Sep 2022 05:50:04 PM UTC] Creating domain key
[Sun 25 Sep 2022 05:50:05 PM UTC] The domain key is here: /shared/letsencrypt/www.starzen.space/www.starzen.space.key
[Sun 25 Sep 2022 05:50:05 PM UTC] Multi domain='DNS:www.starzen.space,DNS:starzen.space'
[Sun 25 Sep 2022 05:50:05 PM UTC] Getting domain auth token for each domain
[Sun 25 Sep 2022 05:50:08 PM UTC] Getting webroot for domain='www.starzen.space'
[Sun 25 Sep 2022 05:50:08 PM UTC] Getting webroot for domain='starzen.space'
[Sun 25 Sep 2022 05:50:08 PM UTC] www.starzen.space is already verified, skip http-01.
[Sun 25 Sep 2022 05:50:08 PM UTC] Verifying: starzen.space
[Sun 25 Sep 2022 05:50:12 PM UTC] Pending
[Sun 25 Sep 2022 05:50:15 PM UTC] Success
[Sun 25 Sep 2022 05:50:15 PM UTC] Verify finished, start to sign.
[Sun 25 Sep 2022 05:50:15 PM UTC] Lets finalize the order.
[Sun 25 Sep 2022 05:50:15 PM UTC] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/590255196/128806215177'
[Sun 25 Sep 2022 05:50:16 PM UTC] Downloading cert.
[Sun 25 Sep 2022 05:50:16 PM UTC] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/03ff6b1b76f8516165032c6c2e02205a529b'
[Sun 25 Sep 2022 05:50:17 PM UTC] Cert success.
-----BEGIN CERTIFICATE-----
Lotsofcrazytext
-----END CERTIFICATE-----
[Sun 25 Sep 2022 05:50:17 PM UTC] Your cert is in  /shared/letsencrypt/www.starzen.space/www.starzen.space.cer 
[Sun 25 Sep 2022 05:50:17 PM UTC] Your cert key is in  /shared/letsencrypt/www.starzen.space/www.starzen.space.key 
[Sun 25 Sep 2022 05:50:17 PM UTC] The intermediate CA cert is in  /shared/letsencrypt/www.starzen.space/ca.cer 
[Sun 25 Sep 2022 05:50:17 PM UTC] And the full chain certs is there:  /shared/letsencrypt/www.starzen.space/fullchain.cer 
[Sun 25 Sep 2022 05:50:17 PM UTC] Installing key to:/shared/ssl/www.starzen.space.key
[Sun 25 Sep 2022 05:50:17 PM UTC] Installing full chain to:/shared/ssl/www.starzen.space.cer
[Sun 25 Sep 2022 05:50:17 PM UTC] Run reload cmd: sv reload nginx
ok: run: nginx: (pid 579) 35281s
[Sun 25 Sep 2022 05:50:17 PM UTC] Reload success
[Sun 25 Sep 2022 05:50:18 PM UTC] Domains not changed.
[Sun 25 Sep 2022 05:50:18 PM UTC] Skip, Next renewal time is: Wed 23 Nov 2022 10:01:01 AM UTC
[Sun 25 Sep 2022 05:50:18 PM UTC] Add '--force' to force to renew.
[Sun 25 Sep 2022 05:50:18 PM UTC] Installing key to:/shared/ssl/www.starzen.space_ecc.key
[Sun 25 Sep 2022 05:50:18 PM UTC] Installing full chain to:/shared/ssl/www.starzen.space_ecc.cer
[Sun 25 Sep 2022 05:50:18 PM UTC] Run reload cmd: sv reload nginx
ok: run: nginx: (pid 579) 35282s

¡Mayormente un gran éxito! curl ahora es mucho más amable y me da la redirección:

blah discourse % curl https://starzen.space

301 Moved Permanently
301 Moved Permanently
nginx/1.21.6

Y https://starzen.space en Firefox y Chrome ahora funciona, redirigiendo al subdominio correcto, pero todavía obtengo el temido gráfico de la fatalidad en Safari, ¿qué pasa? Incluso lo he reiniciado, he borrado las cachés para este sitio:

Mirando el certificado desde el navegador, veo:

1 me gusta

He estado queriendo echarle un vistazo más de cerca. Creo que ahora hay dos lugares en la plantilla de Let’s Encrypt donde debe ir el dominio adicional. No creo que necesites hacer ningún cambio en las cosas de nginx porque ya está haciendo 301 a cualquier cosa que no sea el nombre de host.

Lo que hay que hacer es mirar la plantilla de Let’s Encrypt y ver dónde está poniendo el nombre de host y ver que estás haciendo lo mismo con el nombre de host adicional.

3 Me gusta

Sí, gracias, lo hice por completitud y todavía no parece haber ningún daño en ello, pero estaré encantado de reconstruirlo sin él en algún momento.

¿Parece que hay dos conjuntos de archivos criptográficos?:

root@starship-enterprise:/shared/letsencrypt# cd starzen.space
root@starship-enterprise:/shared/letsencrypt/starzen.space# ls
backup	ca.cer	fullchain.cer  starzen.space.cer  starzen.space.conf  starzen.space.csr  starzen.space.csr.conf  starzen.space.key
root@starship-enterprise:/shared/letsencrypt/starzen.space# cd ..
root@starship-enterprise:/shared/letsencrypt# cd www.starzen.space
root@starship-enterprise:/shared/letsencrypt/www.starzen.space# ls
backup	    ca.cer	   www.starzen.space.cer   www.starzen.space.csr       www.starzen.space.key
backup_two  fullchain.cer  www.starzen.space.conf  www.starzen.space.csr.conf
root@starship-enterprise:/shared/letsencrypt/www.starzen.space# 

Ah, ¿podría ser aquí (y abajo)?

¿Solo está incluyendo información para el nombre de host, no para el apex?

1 me gusta

No, creo que esto es correcto. Debería haber un certificado y debería funcionar tanto para www. como para el apex.

Esta herramienta sugiere que solo hay un dominio en mi certificado público (¿lo que sería la fuente del problema?):

1 me gusta

Necesitas cambiar la parte de Let’s Encrypt que obtiene el certificado. Necesita solicitar el certificado único para ambos dominios. Estas instrucciones solían funcionar, pero creo que algo cambió en la forma en que se solicita el certificado. Si obtiene el certificado correcto, todo lo demás funciona.

1 me gusta

Si ejecutas certbot certificates, se mostrarán tus certificados y los dominios que cubren. Si no cubre tanto el apex como el www, puedes

  1. ejecutar certbot de nuevo y hacer que cree un certificado tanto para el apex como para el www;

Si eliges esta opción, ejecuta certbot certificates para obtener el nombre del certificado que deseas eliminar. Ejecuta certbot delete (nombre del certificado que deseas eliminar). Deberías quedarte solo con tu nuevo certificado (con el apex y el www).

o (lo más fácil)

  1. ejecuta `certbot --expand -d existing.domain -d added.domain

Esto actualizará tu certificado con un nuevo certificado que contendrá el dominio original y los que añadas con el indicador -d.

2 Me gusta

Jim, ¿comando certbot no encontrado? ¿es esto parte de la instalación estándar y solo hay un problema de ruta?

1 me gusta

Sin mirar realmente… Creo que certbot es lo que normalmente usas, pero dentro del contenedor discourse usaba acme.

Y también relacionado, ¿estás intentando esto dentro o fuera del contenedor?

(Además, mi día se está llenando y es posible que no pueda examinar esto tan cuidadosamente como pensaba, pero ha estado en mi lista)

3 Me gusta

De acuerdo… creo que una forma de hacerlo es esta?:

Si uso desde cualquier línea de comandos de Linux adecuada

true | openssl s_client -connect www.starzen.space:443 2>/dev/null \
| openssl x509 -noout -text \
| perl -l -0777 -ne '@names=/\\bDNS:([^\\s,]+)/g; print join("\\n", sort @names);'

Solo obtengo un dominio y falta el apex.

1 me gusta

Dentro del contenedor encuentras el código que solicita (¿y renueva?) el certificado y ves que lo solicita para ambos dominios.

1 me gusta

Sí, lo es, según:

LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh --issue $2 -d www.starzen.space -d starzen.space --keylength

Y puedes ver esto en la salida del registro anterior.

Sin embargo, hay otros pasos de instalación de certificados que solo incluyen -d www.starzen.space, ¿lo que podría ser un problema? Aunque si este certificado está construido para ambos, tal vez ese no sea el problema…

1 me gusta

Eso es lo que he estado tratando de decir. Parece que también necesitas actualizar esos. No estoy seguro de por qué ahora hay varios, pero el OP necesita ser actualizado con código para cambiar todos esos pasos. O eso creo.

4 Me gusta

Sí, voy a intentarlo, al principio manualmente

2 Me gusta

Bien. Eso es lo que iba a hacer. Quizás te he engañado para que lo hagas. :winking_face_with_tongue:

1 me gusta

Tiene sentido intentarlo, solo que podría tener que reconstruir el contenedor para instalar nano… :sweat_smile:

1 me gusta

¡No!

 apt-get update; apt-get install nano

Puedes ejecutar eso dentro del contenedor. Yo lo hago todo el tiempo (excepto que uso vim)

3 Me gusta

Lamentablemente, eso no funcionó:

root@starship-enterprise:/etc/runit/1.d# ./letsencrypt 
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()
[Mon 26 Sep 2022 12:35:54 PM UTC] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Mon 26 Sep 2022 12:35:54 PM UTC] Creating domain key
[Mon 26 Sep 2022 12:35:56 PM UTC] The domain key is here: /shared/letsencrypt/www.starzen.space/www.starzen.space.key
[Mon 26 Sep 2022 12:35:56 PM UTC] Multi domain='DNS:www.starzen.space,DNS:starzen.space'
[Mon 26 Sep 2022 12:35:56 PM UTC] Getting domain auth token for each domain
[Mon 26 Sep 2022 12:35:59 PM UTC] Getting webroot for domain='www.starzen.space'
[Mon 26 Sep 2022 12:35:59 PM UTC] Getting webroot for domain='starzen.space'
[Mon 26 Sep 2022 12:35:59 PM UTC] www.starzen.space is already verified, skip http-01.
[Mon 26 Sep 2022 12:35:59 PM UTC] starzen.space is already verified, skip http-01.
[Mon 26 Sep 2022 12:36:00 PM UTC] Verify finished, start to sign.
[Mon 26 Sep 2022 12:36:00 PM UTC] Lets finalize the order.
[Mon 26 Sep 2022 12:36:00 PM UTC] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/590255196/129044627717'
[Mon 26 Sep 2022 12:36:01 PM UTC] Downloading cert.
[Mon 26 Sep 2022 12:36:01 PM UTC] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/03ffc90cecd2f11f2ba386da2d501127aee5'
[Mon 26 Sep 2022 12:36:02 PM UTC] Cert success.
-----BEGIN CERTIFICATE-----
phewbigcert
-----END CERTIFICATE-----
[Mon 26 Sep 2022 12:36:02 PM UTC] Your cert is in  /shared/letsencrypt/www.starzen.space/www.starzen.space.cer 
[Mon 26 Sep 2022 12:36:02 PM UTC] Your cert key is in  /shared/letsencrypt/www.starzen.space/www.starzen.space.key 
[Mon 26 Sep 2022 12:36:02 PM UTC] The intermediate CA cert is in  /shared/letsencrypt/www.starzen.space/ca.cer 
[Mon 26 Sep 2022 12:36:02 PM UTC] And the full chain certs is there:  /shared/letsencrypt/www.starzen.space/fullchain.cer 
[Mon 26 Sep 2022 12:36:02 PM UTC] Installing key to:/shared/ssl/www.starzen.space.key
[Mon 26 Sep 2022 12:36:02 PM UTC] Installing full chain to:/shared/ssl/www.starzen.space.cer
[Mon 26 Sep 2022 12:36:02 PM UTC] Run reload cmd: sv reload nginx
ok: run: nginx: (pid 2970) 329s
[Mon 26 Sep 2022 12:36:02 PM UTC] Reload success
[Mon 26 Sep 2022 12:36:03 PM UTC] Domains not changed.
[Mon 26 Sep 2022 12:36:03 PM UTC] Skip, Next renewal time is: Wed 23 Nov 2022 10:01:01 AM UTC
[Mon 26 Sep 2022 12:36:03 PM UTC] Add '--force' to force to renew.
[Mon 26 Sep 2022 12:36:04 PM UTC] Installing key to:/shared/ssl/www.starzen.space_ecc.key
[Mon 26 Sep 2022 12:36:04 PM UTC] Installing full chain to:/shared/ssl/www.starzen.space_ecc.cer
[Mon 26 Sep 2022 12:36:04 PM UTC] Run reload cmd: sv reload nginx
ok: run: nginx: (pid 2970) 331s
[Mon 26 Sep 2022 12:36:04 PM UTC] Reload success

Lo que todavía parece haber expuesto un certificado con un solo dominio…

true | openssl s_client -connect www.starzen.space:443 2>/dev/null \
| openssl x509 -noout -text \
| perl -l -0777 -ne '@names=/\\bDNS:([^\\s,]+)/g; print join("\\n", sort @names);'
www.starzen.space
1 me gusta