Como executar o Discourse como um VirtualHost do Apache

Consegui instalar o Discourse com sucesso no meu servidor, registrar o primeiro usuário e publicar meu primeiro tópico. Portanto, tudo parece estar funcionando do lado do Discourse.

No entanto, para instalar e executar o Discourse, precisei desativar meu daemon Apache httpd. Isso é um grande problema para mim, pois basicamente desliguei todo o meu servidor web, que inclui vários domínios, além de um servidor de conferência Jitsi.

Minha instalação do Jitsi roda como um virtual host separado usando um subdomínio de um dos sites que estou hospedando. Como o Jitsi consegue compartilhar a porta 443 com o restante do tráfego web, gostaria de fazer o mesmo com o Discourse.

Alguém tem um modelo de definição de virtualhost que permita que o tráfego seja direcionado para o Discourse quando chegar no subdomínio do Discourse?

Sim, há guias aqui no Meta que discutem a execução do Discourse junto com outros sites.

Tenho certeza de que, se você usar a busca, poderá encontrá-los.

Essencialmente resolvido, no entanto a página inicial parece levar muito tempo para finalizar a requisição, mesmo após a página parecer estar totalmente carregada. (Não tenho certeza se esse é um comportamento normal ou não.)

Discourse
Modifiquei o bloco expose em /var/discourse/containers/app.yml para:

expose:
  - "127.0.0.1:8000:80"   # http
  - "127.0.0.1:8443:443"  # https

Isso encaminha do localhost para o contêiner Docker. Após fazer isso, é necessário executar um rebuild usando ./launcher rebuild app

Apache2 2.4.43 (Ubuntu)
Adicionei um novo virtual host para o subdomínio: discourse..com.conf em sites-available, que encaminha o tráfego do subdomínio para a porta localhost na qual a instância Docker do Discourse está escutando. A definição do virtual host está abaixo:

<VirtualHost *:80>
    ServerName discourse.<myDomain>.com
    Redirect permanent / https://discourse.<myDomain>.com/
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

<VirtualHost *:443>

  ServerName discourse.<myDomain>.com

  SSLProtocol TLSv1 TLSv1.1 TLSv1.2
  SSLEngine on
  SSLProxyEngine on
  SSLCertificateFile /etc/letsencrypt/live/<myDomain>.com/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/<myDomain>.com/privkey.pem
  SSLCACertificateFile /etc/letsencrypt/live/<myDomain>.com/chain.pem
  SSLCipherSuite "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL:!eNULL:!MEDIUM:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SEED"
  SSLHonorCipherOrder on
  Header set Strict-Transport-Security "max-age=31536000"

  <Location />
    Order allow,deny
    Allow from all
    Require all granted
  </Location>

  ProxyPreserveHost on
  ProxyRequests Off
  RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
  RequestHeader set X-Real-IP expr=%{REMOTE_ADDR}
  ProxyPass / https://127.0.0.1:8443/
  ProxyPassReverse / https://127.0.0.1:8443/

</VirtualHost>

Como não passo muito tempo configurando o Apache, pode haver algumas linhas desnecessárias, ou linhas que poderiam ser adicionadas ou melhoradas. Qualquer feedback é bem-vindo.

Olá @Nap,

Bom saber que você resolveu seu problema.

Estou rodando o Discourse em vários servidores com o Apache2 como proxy reverso de front-end para um socket Unix, e a configuração funciona perfeitamente (como todos sabemos, é um pouco mais lento que o nginx, que também uso em alguns servidores, mas funciona bem.)

Basicamente, configuro o virtual host assim:

Configuração da porta 80

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName  discourse.mygreatwebsite.com
    DocumentRoot /website/discourse  # muitas vezes não é necessário

    RewriteEngine On
    ProxyPreserveHost On
    ProxyRequests Off
    ErrorLog /var/log/apache2/discourse.error.log
    LogLevel warn
    CustomLog /var/log/apache2/discourse.access.log combined

    RewriteCond %{SERVER_NAME} =discourse.mygreatwebsite.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

Configuração da porta 443:

<VirtualHost *:443>
  ServerAdmin webmaster@localhost
  ServerName  discourse.mygreatwebsite.com
  DocumentRoot /website/nginx  # na maioria das vezes não é necessário nesta configuração
  
  SSLProxyEngine on
  RewriteEngine On
  ProxyPreserveHost On
  ProxyRequests Off
  RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
  RequestHeader set X-Real-IP expr=%{REMOTE_ADDR}
  
  ProxyPass / unix:/var/discourse/shared/socket-only/discourse.http.sock|http://my.ip.address.here/
  ProxyPassReverse  / unix:/var/discourse/shared/socket-only/discourse.http.sock|http://my.ip.address.here/
  ErrorLog /var/log/apache2/discourse-ssl.error.log
  LogLevel warn
  CustomLog /var/log/apache2/discourse-ssl.access.log combined

  Include /etc/letsencrypt/options-ssl-apache.conf
  SSLCertificateFile /etc/letsencrypt/live/discourse.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/discourse.com/privkey.pem
</VirtualHost>

Observações:

  1. Normalmente, deixo o letsecrypt certbot fazer todo o trabalho relacionado à configuração de todos os certificados SSL e redirecionamentos, etc.

  2. Usamos o endereço IP ao qual o apache2 está vinculado nos arquivos de configuração do apache2.

  3. Sempre configuramos isso (expondo) com sockets Unix no contêiner do Discourse e não expomos nenhuma porta TCP/IP do contêiner nesta configuração.

Abraços e espero que isso adicione algum valor, mesmo no final do jogo.

Duas adições rápidas:

  1. Se você preferir usar um socket Unix em vez de um proxy direto, é possível fazê-lo (após habilitar o web.socketed.template.yml no seu app.yml) da seguinte forma:
  ProxyPreserveHost On
  ProxyRequests Off
  RequestHeader set X-Forwarded-Proto https
  RequestHeader set X-Real-IP expr=%{REMOTE_ADDR}
  <Location />
    ProxyPass unix:/var/discourse/shared/standalone/nginx.http.sock|http://localhost/
    ProxyPassReverse unix:/var/discourse/shared/standalone/nginx.http.sock|http://localhost/
  </Location>

Observe que, provavelmente, você precisará lidar com o SELinux se tentar fazer o Apache ler de /var/discourse dessa maneira. Algo como semanage fcontext -a -t httpd_sys_rw_content_t /var/discourse/shared/standalone/nginx.http.sock, seguido de restorecon /var/discourse/shared/standalone/nginx.http.sock, deve resolver isso.

  1. O Apache possui o excelente mod_md, que pode obter automaticamente seus certificados LetsEncrypt. Recomendo fortemente.