Erro no Bootstrap durante a instalação do Discourse: ENOENT - /etc/runit/1.d/letsencrypt

Olá, estou tentando instalar o Discourse usando o processo padrão ./discourse-setup, mas estou encontrando um erro durante o bootstrap:

FAILED
--------------------
Errno::ENOENT: No such file or directory @ rb_sysopen - /etc/runit/1.d/letsencrypt
Location of failure: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/replace_command.rb:11:in `read'
replace failed with the params {"filename"=>"/etc/runit/1.d/letsencrypt", "from"=>"/--keylength/", "to"=>"-d forum.mysite.org --keylength"}
bootstrap failed with exit code 1
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.

Parece que o erro é acionado por um plugin que tenta executar um comando replace no arquivo /etc/runit/1.d/letsencrypt, que não existe dentro do contêiner durante o bootstrap. A linha relevante no plugin se parece com isto:

- replace:
    filename: "/etc/runit/1.d/letsencrypt"
    from: "/--keylength/"
    to: "-d forum.mysite.org --keylength"

Algum conselho sobre como corrigir isso ou regenerar adequadamente o arquivo ausente?

Agradeço antecipadamente.

Um plugin? Esse é o código cups do seu app.yml, certo? Você está tentando adicionar outro certificado? Como em Set up Let’s Encrypt with multiple domains / redirects Você pode incluir o código real e ambos os certificados?

Como você apontou, esse runit não existe mais, e agora essa mágica está em /usr/local/bin/letsencrypt (dentro do contêiner)

Eu acho que você pode querer algo como isso se o seu site for www.mysite.org e você também quiser que ele tenha um certificado para forum.mysite.org:

- replace:
    filename: "/usr/local/bin/letsencrypt"
    from: "/-d www.mysite.org/"
    to: "-d www.mysite.org -d forum.mysite.org "
    global: true

O que eu faria (o que pode não ser útil para você) é entrar no contêiner, apt update;apt install -y vim e então editar /usr/local/bin/letsencrypt de forma que ele solicite os certificados que você deseja.

Adicionei código ao tópico let’s encrypt vinculado acima que deve permitir que você insira seu domínio e obtenha código que você pode copiar/colar em seu app.yml.

1 curtida

Encontrei uma mensagem de erro semelhante durante uma tentativa de atualização.

Não estou tentando mudar nada relacionado a certificados.

Meu arquivo app.yml mostra isto atualmente:

 after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d www.nzarchitecture.net.nz --keylength"

Segui sua sugestão:

 apt update;apt install -y vim

mas o resultado foi ‘vim já é a versão mais recente (2:9.1.0016-1ubuntu7.8).’

Quanto ao segundo passo sugerido, não tenho ideia de quais certificados eu quero, pois não tive a intenção de mudar nada.

OK, depois de algumas horas de luta, consegui voltar a funcionar.

Encontrei um arquivo app.yml antigo e o substituí, apenas excluindo as referências antigas a plugins que desde então foram incorporados ao Discourse.

Este arquivo app.yml mais antigo não continha o código abaixo, que encontrei em um posterior.

 after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d www.nzarchitecture.net.nz --keylength"

Não me lembro de ter colocado esse código lá, embora eu tivesse configurado meu site para usar letsencrypt para os certificados de segurança gratuitos, mas as instruções em Set up HTTPS support with Let's Encrypt não parecem exigir essas linhas, então não faço ideia para que teriam servido.

Alguma outra coisa poderia ter potencialmente gravado essas linhas no app.yml? Por exemplo, poderiam ter sido adicionadas durante uma atualização beta?

Pelo menos por enquanto, com essas linhas removidas, meu site está funcionando novamente e atualizado.

Quando meu certificado SSL atual expirar, acho que descobrirei para que serviam essas linhas extras.

Bem, você está, mas não se lembra. :wink:

Se você tem essa seção after_ssl no seu arquivo yml, então em algum momento você configurou as coisas de forma que, se alguém colocasse um www na frente do seu domínio, ele iria para o endereço www e seria redirecionado para o endereço não-www sem um erro de certificado.

Minha sugestão foi instalar o vim dentro do container e tentar mexer nos arquivos lá, mas acho que meu código para adicionar ao app.yml deve funcionar.

Certo. E agora, se você visitar https://www.nzarchitecture.net.nz/, você terá um erro de certificado. Você poderia usar https://forcewww.com/

Você poderia ir ao link acima e obter o novo código que eu acho que deve funcionar, mas não testei, pois não encontrei um site que estou atualizando que precise dele.

Estou correto em pensar que seu código seria algo como as linhas abaixo, se eu quiser que www.nzarchitecture.net.nz seja coberto pelo mesmo certificado letsencrypt que nzarchitecture.net.nz?

after_ssl:
    - replace:
        filename: /usr/local/bin/letsencrypt
        from: /-d nzarchitecture.net.nz /
        to: "-d nzarchitecture.net.nz -d www.nzarchitecture.net.nz "
        global: true

Eu tentei adicionar esta seção (ótima terminologia, obrigado!) ao final de app.yml, em vez da seção original ‘after_ssl:’, e agora consigo reconstruir o Discourse sem erros - mas isso não parece me ajudar; meu navegador ainda exibe uma resposta ‘net::ERR_CERT_COMMON_NAME_INVALID’ se eu tentar usar um prefixo ‘www’ antes do meu domínio principal/certificado nzarchitecture.net.nz

Meu app.yml completo abaixo, caso ajude em alguma coisa (senha e endereços de e-mail omitidos)

## este é o template completo e independente do container Docker do Discourse
##
## Após fazer alterações neste arquivo, VOCÊ DEVE reconstruir
## /var/discourse/launcher rebuild app
##
## TENHA MUITO CUIDADO AO EDITAR!
## ARQUIVOS YAML SÃO SUPER SUPER SENSÍVEIS A ERROS DE ESPAÇAMENTO OU ALINHAMENTO!
## visite http://www.yamllint.com/ para validar este arquivo conforme necessário

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## Descomente estas duas linhas se desejar adicionar Lets Encrypt (https)
  - "templates/web.ssl.template.yml"
  - "templates/web.letsencrypt.ssl.template.yml"
  - "templates/import/mysql-dep.template.yml"

## quais portas TCP/IP este container deve expor?
## Se você quiser que o Discourse compartilhe uma porta com outro servidor web como Apache ou nginx,
## veja https://meta.discourse.org/t/17247 para detalhes
expose:
  - "80:80"   # http
  - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## Defina db_shared_buffers para um máximo de 25% da memória total.
  ## será definido automaticamente pelo bootstrap com base na RAM detectada, ou você pode substituir
  db_shared_buffers: "128MB"

  ## pode melhorar o desempenho da ordenação, mas adiciona uso de memória por conexão
  #db_work_mem: "40MB"

  ## Qual revisão Git este container deve usar? (padrão: tests-passed)
  #version: tests-passed

env:
  LANG: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## Quantas requisições web concorrentes são suportadas? Depende da memória e dos núcleos da CPU.
  ## será definido automaticamente pelo bootstrap com base nas CPUs detectadas, ou você pode substituir
  UNICORN_WORKERS: 2

  ## TODO: O nome de domínio que esta instância do Discourse responderá
  ## Obrigatório. O Discourse não funcionará com um número IP puro.
  DISCOURSE_HOSTNAME: nzarchitecture.net.nz

  ## Descomente se você quiser que o container seja iniciado com o mesmo
  ## nome de host (-h option) especificado acima (padrão "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: Lista de e-mails separados por vírgula que serão feitos administradores e desenvolvedores
  ## na inscrição inicial exemplo 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: '****************'

  ## TODO: O servidor de e-mail SMTP usado para validar novas contas e enviar notificações
  # ENDEREÇO SMTP, nome de usuário e senha são necessários
  # AVISO o caractere '#' na senha SMTP pode causar problemas!
  DISCOURSE_SMTP_ADDRESS: smtp.mailgun.org
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: ****************
  DISCOURSE_SMTP_PASSWORD: "****************"
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (opcional, padrão true)

  ## Se você adicionou o template Lets Encrypt, descomente abaixo para obter um certificado SSL gratuito
  LETSENCRYPT_ACCOUNT_EMAIL: ******************

  ## O endereço CDN http ou https para esta instância do Discourse (configurado para puxar)
  ## veja https://meta.discourse.org/t/14857 para detalhes
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

## O container Docker é sem estado; todos os dados são armazenados em /shared
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Plugins vão aqui
## veja https://meta.discourse.org/t/19157 para detalhes
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-bbcode.git
## Quaisquer comandos personalizados para executar após a construção
run:
  - exec: echo "Início dos comandos personalizados"
  ## Se você quiser definir o endereço de e-mail 'De' para seu primeiro registro, descomente e altere:
  ## Após receber o primeiro e-mail de inscrição, comente a linha novamente. Ela só precisa ser executada uma vez.
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  - exec: echo "Fim dos comandos personalizados"

after_ssl:
    - replace:
        filename: /usr/local/bin/letsencrypt
        from: /-d nzarchitecture.net.nz /
        to: "-d nzarchitecture.net.nz -d www.nzarchitecture.net.nz "
        global: true

O fato de não haver arquivos em /usr/local/bin/ é parte do problema?

Onde encontro o arquivo letsencrypt correto para colocar lá, se é isso que é necessário?

E, se ‘letsencrypt’ for o nome do arquivo no final desse caminho, é normal que não haja extensão de arquivo como parte deste nome de arquivo?

Minha ideia é remover a linha after_ssl e desindentar as outras.

Se você adicionar minha chave SSH com

ssh-import-id-gh pfaffman

e me enviar um e-mail, verei o que posso fazer.

Obrigado! @pfaffman

Acabei de te enviar um e-mail agora

Aqui está uma atualização.

Adicionar isto à seção run na parte inferior do seu app.yml resolverá o problema de fazer com que /usr/local/bin/letsencrypt solicite certificados para DISCOURSE_HOSTNAME e www.DISCOURSE_HOSTNAME.

- exec: sed -i "s|-d \\${DISCOURSE_HOSTNAME}|-d \\${DISCOURSE_HOSTNAME} -d www.\\${DISCOURSE_HOSTNAME}|g" /usr/local/bin/letsencrypt

Isto (de alguma forma?) costumava ser suficiente, mas agora, quando o pedido chega para http://www.HOSTNAME/.well-known…, ele é redirecionado para o site não-www em vez de enviar o desafio que deveria enviar. Eu tentei fazer algo como isto:

server {
  listen 80;
  listen [::]:80;
  server_name nzarchitecture.net.nz www.nzarchitecture.net.nz;

  # Serve o desafio ACME (Let's Encrypt)
  location ^~ /.well-known/acme-challenge/ {
    root /var/www/discourse/public;  # Certifique-se de que isto corresponda à sua webroot do Let's Encrypt
    allow all;
  }

  # Redireciona todo o resto para HTTPS
  location / {
    return 301 https://$host$request_uri;
  }
}

mas não descobri completamente.

Se alguém da equipe estiver ouvindo, seria bom se houvesse um hook do letsencrypt para que isso pudesse ser chamado em um after_letsencrypt. Antes de fazer essas alterações em after_ssl funcionava, mas parece que agora, se fizermos isso, ele é executado após o ssl, mas antes do letsencrypt.

3 curtidas

Estou vendo esse problema também. Avisarei se conseguir consertar.

Meu DISCOURSE_HOSTNAME é www.textkit.com. Estou fazendo o oposto de nzarchitecture.net.nz e adicionando um hostname sem www ao meu certificado. Isso funcionou para mim:

- exec: sed -i \"s|-d \\${DISCOURSE_HOSTNAME}|-d www.textkit.com -d textkit.com|g\" /usr/local/bin/letsencrypt

Não consigo dizer por que @pfaffman e nzarchitecture.net.nz estariam tendo problemas com a versão dele, embora talvez a ordem do hostname na minha seja relacionada.

Eu também passei por isso.

Removi isto (comentando):

  after_ssl:
#    - replace:
#        filename: "/etc/runit/1.d/letsencrypt"
#        from: /--keylength/
#        to: "-d example.com --keylength"
#    - replace:
#        filename: "/etc/nginx/conf.d/discourse.conf"
#        from: /return 301 https.+/
#        to: |
#          return 301 https://$host$request_uri;

e adicionei isto na seção run na parte inferior, conforme @pfaffman:

- exec: sed -i "s|-d \\${DISCOURSE_HOSTNAME}|-d \\${DISCOURSE_HOSTNAME} -d www.\\${DISCOURSE_HOSTNAME}|g" /usr/local/bin/letsencrypt

Isso parece ter sido suficiente para mim:

  • o site foi reconstruído e aparentemente parece ter certificados válidos
  • o redirecionamento do apex para www está funcionando

Obrigado @pfaffman!

4 curtidas

Ah! Legal. Talvez a alteração que eles fizeram, que permitiu que as renovações de certificado funcionassem, também resolveu o problema que eu estava enfrentando.

Vou me lembrar disso se encontrar outros sites que precisem disso antes que o PR seja aceito.

1 curtida

Há algumas partes móveis aqui. Funcionou para mim naquela reconstrução, reportarei aqui se essa situação mudar!

1 curtida

O PR para permitir renovações de certificado ainda não foi mesclado – essa parte ainda está pendente.

Assim que for mesclado, isso deve permitir um app.yml muito mais simplificado.

2 curtidas

Estranhamente, esse trecho de código funciona em um dos meus sites, mas o código antigo (e apenas o código antigo) funciona no meu outro site. :person_shrugging:

Bem, espero que tudo isso seja irrelevante em breve de qualquer forma!

1 curtida

Isso é muito estranho. O discourse_docker está fixado em uma versão antiga?

Não, não é. Não há muita diferença entre as instâncias (temas/plugins/configurações semelhantes), exceto que uma instância é bem mais antiga que a outra.

Bem, espero que isso seja apenas acadêmico.

1 curtida

Isso foi implementado de alguma forma?

Meu certificado LetsEncrypt acabou de expirar ontem sem renovação automática. Não tenho certeza se isso tem algo a ver com as alterações sugeridas no app.yml que fiz de acordo com este tópico acima, ou com atualizações subsequentes do Discourse.

Com assistência de IA (sim, eu sei!) consegui fazê-lo renovar, depois de seguir a IA por vários becos sem saída envolvendo o uso de ngix e certbot (o que acabou funcionando, para ser justo), antes de reverter essas alterações e voltar ao método padrão gerenciado pelo Discourse. No processo, tive que reconstruir algumas vezes, então não tenho certeza se foi isso que acionou a renovação.

Desculpe pelo transtorno - estou curioso, quando foi a última vez que você reconstruiu antes desta?

Acabamos de verificar e testar o processo de renovação novamente, mas não conseguimos reproduzir - nossos testes renovam corretamente, então ou algo não está acontecendo do nosso lado, ou há algo diferente na forma como a renovação do staging versus a produção do Let’s Encrypt funciona.

Também posso confirmar que reconstruir seu site força o processo de renovação a ocorrer, se tudo mais falhar.

Usamos o acme.sh por baixo dos panos (em /opt/acme.sh no contêiner) - se você estiver inclinado, pode entrar no contêiner docker em execução e executar o script para inspecionar/renovar por lá também.

1 curtida