Configurar Let's Encrypt com vários domínios / redirecionamentos

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 curtidas

Obrigado, isso funciona para redirecionar “www.example.com” para “comunnity.example.com”?
Ou como posso fazer isso?
Tenho problemas com meu domínio www.example.com, configurei o DNS para redirecionar para comunnity.example.com, mas não funciona no Firefox ou Chrome.

2 curtidas

Existe uma ferramenta de verificação de redirecionamento para verificar seus redirecionamentos.

5 curtidas

Estou com um pouco de dificuldade com isso. Ok, com muita dificuldade.

Decidi experimentar adicionar uma CDN a um dos meus sites.

Depois de ler a documentação, percebi que seria melhor para o meu site mudar para um subdomínio do seu domínio apex atual, a fim de cumprir os critérios recomendados pela Fastly (e o conselho geral para fazê-lo).

Então pensei: “meh, isso vai ser moleza, já fiz isso antes…”. ah, é mesmo?! :sweat_smile:
O site em questão é https://starzen.space.

Mudei-o neste fim de semana para https://www.starzen.space usando o guia aqui

Tudo correu bem, MAS é claro que ainda preciso considerar a pequena quantidade de usuários que já consegui neste site, então queria adicionar um redirecionamento.

Pelo que entendi, também preciso do link original emitido com um certificado, então seguindo este guia (que costumava ser muito mais envolvido?) adicionei isto 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;
          }

Numa reconstrução, tudo parece correr bem.

No entanto, se eu tentar aceder a https://starzen.space através de um navegador, recebo:

E se eu fizer 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.

Tenho a certeza de que é o certificado que está a falhar, porque se executar o mesmo em modo inseguro, recebo:

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

301 Moved Permanently
301 Moved Permanently
nginx/1.21.6

o que acredito ser o que eu quero.

Penso que o script modificado está correto, é o que tenho:

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>

Até executei isto a partir da linha de comando dentro do container, antes do qual movi todos os ficheiros de certificado do diretório de destino para um diretório de backup para que o comando correto fosse executado para o domínio duplo:

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] 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
[Sun 25 Sep 2022 05:50:18 PM UTC] Reload success

Maior sucesso!!!, o curl está muito mais amigável agora e dá-me o redirecionamento:

blah discourse % curl https://starzen.space

301 Moved Permanently
301 Moved Permanently
nginx/1.21.6

E https://starzen.space no Firefox e Chrome agora funciona, redirecionando para o subdomínio correto, mas ainda estou a receber o temido gráfico de perdição no Safari, o que se passa? Já até o reiniciei e limpei os caches para este site:

a dar uma vista de olhos no certificado do navegador, vejo:

1 curtida

Eu estava querendo dar uma olhada mais de perto nisso. Acho que agora existem dois lugares no template do let’s encrypt onde o domínio adicional precisa ir. Não acho que você precise fazer nenhuma alteração nas coisas do nginx porque ele já está fazendo 301 para qualquer coisa que não seja o nome do host.

O que fazer é olhar o template do let’s encrypt e ver onde ele está colocando o nome do host e ver que você está fazendo isso com o nome do host adicional também.

3 curtidas

Sim, obrigado, fiz isso por completude e ainda não parece haver nenhum problema com isso, mas ficarei feliz em reconstruir sem isso em algum momento.

Parece haver dois conjuntos de arquivos 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, poderia ser aqui (e abaixo)

Está incluindo apenas informações para o nome do host, não para o apex?

1 curtida

Não, acho que isso está correto? Deve haver um certificado e ele deve funcionar tanto para www. quanto para o apex.

Esta ferramenta sugere que há apenas um domínio no meu certificado público (que seria a fonte do problema?):

1 curtida

Você precisa alterar a parte do Let’s Encrypt que obtém o certificado. Ele precisa solicitar o certificado único para ambos os domínios. Essas instruções costumavam funcionar, mas algo mudou na forma como o certificado é solicitado, eu acho. Se ele obtiver o certificado certo, todo o resto funcionará.

1 curtida

Se você executar certbot certificates, ele mostrará seus certificados e os domínios que eles cobrem. Se ele não cobrir tanto o apex quanto o www, você pode

  1. executar o certbot novamente e fazer com que ele crie um certificado para o apex e o www;

Se você escolher esta opção, execute certbot certificates para obter o nome do certificado que deseja excluir. Execute certbot delete (nome do certificado que você deseja excluir). Você deve ficar apenas com seu novo certificado (com o apex e o www).

ou (mais fácil)

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

Isso atualizará seu certificado com um novo certificado contendo o domínio original e aqueles que você adicionar com a flag -d.

2 curtidas

Jim, o comando certbot não foi encontrado? Isso faz parte da instalação padrão e há apenas um problema de caminho?

1 curtida

Sem olhar de verdade… Acho que o certbot é o que você normalmente usa, mas dentro do contêiner o discourse usava o acme.

E também relacionado, você está tentando isso dentro ou fora do contêiner?

(Também meu dia está ficando cheio e talvez eu não consiga olhar isso com tanto cuidado quanto eu pensava, mas estava na minha lista)

3 curtidas

Concordo… uma maneira de fazer isso, acredito, é esta?:

Se eu usar a partir de qualquer linha de comando Linux adequada

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);'

Eu só recebo um domínio e está faltando o apex.

1 curtida

Dentro do contêiner você encontra o código que está solicitando (e renovando?) o certificado e vê que ele está solicitando para ambos os domínios.

1 curtida

Sim, está, conforme:

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

E você pode ver isso na saída do log acima.

No entanto, existem algumas outras etapas de instalação de certificado que incluem apenas -d www.starzen.space, o que pode ser um problema? Embora, se este certificado for construído para ambos, talvez esse não seja o problema…

1 curtida

É isso que venho tentando dizer. Parece que você precisa atualizar essas também. Não tenho certeza por que agora existem várias, mas o OP precisa ser atualizado com o código para alterar todas essas etapas. Ou assim eu penso.

4 curtidas

Sim, vou tentar isso, primeiro manualmente

2 curtidas

Que bom. Era o que eu ia fazer. Talvez eu tenha te enganado para fazer isso. :winking_face_with_tongue:

1 curtida

É sensato tentar, só que talvez eu precise reconstruir o contêiner para instalar o nano… :sweat_smile:

1 curtida

Não!

 apt-get update; apt-get install nano

Você pode simplesmente executar isso dentro do contêiner. Eu faço isso o tempo todo (exceto que eu uso vim)

3 curtidas

Infelizmente, isso não funcionou:

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

O que ainda parece ter exposto um certificado com um único domínio…

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 curtida