DiscourseConnect gera redirecionamentos HTTP mesmo com force_https ativado

Estou executando o Discourse atrás do Traefik em uma configuração personalizada - dar ao Discourse sua própria VM não é uma opção aqui.

Meu Discourse não tem modelos SSL/Let’s Encrypt habilitados, já que o Traefik não permite que solicitações HTTP simples cheguem ao contêiner - ele está configurado para redirecionar solicitações HTTP para HTTPs.

Estou tendo problemas para configurar o DiscourseConnect, porque, como a solicitação Traefik -> nginx[Discourse] é enviada via HTTP de texto simples (porque o nginx não tem SSL configurado), a regra em /etc/nginx/conf.d/discourse.conf que tenta preservar o proto, deve estar em contexto http faz com que o Discourse (o aplicativo Rails) receba uma solicitação HTTP de texto simples, retornando assim um redirecionamento HTTP de texto simples para /session/sso - mesmo que eu tenha force_https habilitado.

Acho que esse é o bug: independentemente da minha configuração, com force_https habilitado, o Discourse sempre deve gerar URLs HTTPs - o que ele não está fazendo.

Acho que o código ofensivo é application_controller#redirect_to_login, mas não investiguei o código-fonte do Discourse o suficiente para ter certeza.

Isso é solucionável no próprio código?

Como solução alternativa, estou tentando adicionar uma regra corrigindo o discourse.conf do nginx para remover essa regra.

Deveríamos ter algum suporte para encaminhamento de cabeçalhos que você usaria para sinalizar ao NGINX qual é a origem

Você definiu
proxy_set_header X-Forwarded-Proto https;

O mais fácil para mim foi definir um rótulo extra no app.yml do Discourse para dizer ao meu Traefik para adicionar um cabeçalho X-Forwarded-Proto: https, mas então o nginx substituiria esse parâmetro pela sua própria versão.

E a configuração do nginx do Discourse desempenha um papel aqui:

Lá, o Discourse tenta adivinhar o protocolo da solicitação original (que, na minha configuração, é sempre texto puro, já que é isso que o Traefik envia). E então usa isso para definir o X-Forwarded-Proto várias vezes.

No final, editei meu containers/app.yml para codificar esses cabeçalhos para https:

run:
  - exec: echo "Beginning of custom commands"
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  # - exec: rails r "SiteSetting.notification_email='no-reply@forum.cabana.network'"
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /# attempt to preserve the proto, must be in http context\nmap \$http_x_forwarded_proto \$thescheme {\n  default \$scheme;\n  "~https$" https;\n}/\n
     to: |
       # force https scheme so Discourse generates HTTPs links and redirects (ie, `/login`)
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: "$thescheme"
     global: "true"
     to: "https"
  - exec: echo "End of custom commands"

Mais uma vez, acho que se houver uma configuração force_https, o Discourse-the-rails-app deveria honrá-la, independentemente do que o proxy reverso ou outras partes lidam ou não.

É assim que fazemos em nossa plataforma de hospedagem; temos uma camada de balanceador de carga que define X-Forwarded-Proto para o nginx+Discourse downstream consumir.

Não precisamos de nenhuma artimanha adicional para fazer funcionar - não tenho certeza do que está dando errado para você aqui.

É de fato o que acontece:

  def self.generate_sso(return_path = "/", secure_session:)
    sso = new(secure_session: secure_session)
    sso.nonce = SecureRandom.hex
    sso.register_nonce(return_path)
    sso.return_sso_url = Discourse.base_url + "/session/sso_login"
    sso
  end

e base_url vem de:

  def self.base_protocol
    SiteSetting.force_https? ? "https" : "http"
  end

  def self.base_url_no_prefix
    "#{base_protocol}://#{current_hostname_with_port}"
  end

  def self.base_url
    base_url_no_prefix + base_path
  end
1 curtida