Discourse con NGINX fuori dal container Docker

In un precedente articolo ho spiegato sommariamente come installare Discourse, il software per la realizzazione di un community forum. Quella modalità di installazione prevede un deployment “autocontenuto”, con tutti i componenti necessari inclusi all’interno un container Docker.

Sebbene sia la modalità di installazione raccomandata, quel tipo di setup comporta che il server (o VPS) sia dedicato interamente a Discourse, senza la possibilità di installare altri siti web. Per ovviare a questa limitazione, è possibile fare in modo di erogare l’applicazione Discourse tramite un’istanza di NGINX esterna al container, in modo tale da poterne gestire la configurazione in maniera arbitraria e più flessibile.

Per utilizzare questa modalità, si può seguire una guida pubblicata sul forum di Discourse, che riassumerò brevemente in questo post.

Per prima cosa bisogna fermare Discourse e provvedere all’installazione di NGINX. Per questo si possono usare i repository della propria distribuzione o, preferibilmente, quelli ufficiali. Se siete utenti avanzati, potete anche pensare di installare NGINX da sorgenti, ma a mio avviso non ci sono grossi vantaggi nel farlo.

Dopo l’installazione, NGINX va configurato per servire il virtualhost del nostro forum con supporto per https.

Infine va modificata la definizione del container dell’applicazione Discourse per fare in modo che il relativo server web sia in ascolto su socket Unix invece che TCP. Fatto questo, si provvede al rebuild dell’applicazione secondo la nuova configurazione.

Stop Discourse

cd /var/discourse
sudo ./launcher stop app

Installazione e configurazione NGINX

Se si vuole installare NGINX usando i pacchetti dei repository della propria distribuzione, è sufficiente utilizzare il rispettivo package manager. Ad esempio, per Debian e derivate:

sudo apt install nginx

Se si vuole installare la versione distribuita direttamente da NGINX, si possono seguire le istruzioni a seconda della distribuzione in uso che trovate qui. Ad esempio, per Ubuntu:

sudo apt install curl gnupg2 ca-certificates lsb-release
echo "deb http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginx
curl -o /tmp/nginx_signing.key https://nginx.org/keys/nginx_signing.key
sudo mv /tmp/nginx_signing.key /etc/apt/trusted.gpg.d/nginx_signing.asc
sudo apt update
sudo apt install nginx

Fatto questo, è necessario creare un semplice virtualhost NGINX per il nostro sito:

server {
     listen 80;
     server_name forum.example.com;
 }

Questa porzione di configurazione si limita a pubblicare un sito web solo sulla porta 80, senza specificare altre informazioni su come servirne i contenuti. Il resto della configurazione lo completeremo dopo aver aggiunto un certificato SSL, ignorando i certificati eventualmente installati in precedenza. Per farlo, utilizziamo certbot, da installare seguendo le relative istruzioni:

sudo systemctl restart nginx
sudo install snap core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx

L’ultimo comando avvia il processo di richiesta del certificato per i domini configurati nel web server. Seguendo le istruzioni, NGINX verrà riconfigurato per erogare il sito su https. Ora è necessario aggiungere alla configurazione la porzione di reverse proxy verso l’applicazione Discourse. Ci limitiamo a farlo solo nella porzione relativa alla porta 443:

server {
  server_name forum.example.com;
  listen 443 ssl http2;
  # impostazioni certificato e parametri ssl
  # aggiunti da certbot
  ....
  ....
  location / {
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
    proxy_set_header Host $http_host;
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Real-IP $remote_addr;
  }
} 

A questo punto si può riavviare NGINX (sudo systemctl restart nginx) e andare avanti.

Riconfigurazione app Discourse

Per modificare la configurazione del container bisogna intervenire sul file /var/discourse/containers/app.yml commentando le righe relative ai template ssl e letsencrypt, alle porte esposte dal container, ed inserendone una per attivare il template socket. Il file risultante sarà quindi del tipo:

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml" # <-- riga che configura NGINX per ascoltare su socket Unix invece che su TCP
## Uncomment these two lines if you wish to add Lets Encrypt (https)
# - "templates/web.ssl.template.yml"
# - "templates/web.letsencrypt.ssl.template.yml"
## which TCP/IP ports should this container expose?
## If you want Discourse to share a port with another webserver like Apache or nginx,
## see https://meta.discourse.org/t/17247 for details
expose:
# - "80:80"   # http
# - "443:443" # https

Procediamo al rebuild col comando:

cd /var/discourse
sudo ./launcher rebuild app

Al termine del processo, il vostro forum sarà accessibile mediante il virtual host NGINX che avete appositamente configurato. Ora siete liberi di aggiungere altri virtualhost per ospitare ulteriori siti web.

Un ultimo accorgimento prima di terminare: se per caso, accedendo al vostro forum, il browser vi avvisa che alcuni contenuti non sono serviti tramite connessione protetta, andate nelle impostazioni del forum e abilitate l’opzione “force https” in Impostazioni –> Sicurezza.