SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-27

Come installare Discourse su un VPS con Docker

Guida all'installer Docker ufficiale di Discourse: RAM e swap, dominio reale, SMTP, app.yml, rebuild, TLS e configurazione con reverse proxy.

Installare Discourse su un VPS: un container, un file di configurazione

Per installare Discourse su un VPS, esegui l'installer fornito dal progetto, rispondi a una breve procedura guidata e attendi la build. Discourse viene distribuito come un unico container Docker che contiene l'applicazione Rails, PostgreSQL, Redis e nginx. Tutto ciò che modificherai in seguito si trova nel file /var/discourse/containers/app.yml e ogni modifica viene applicata al sito tramite una nuova build.

L'installazione ufficiale è discourse_docker: uno script shell launcher e un insieme di template YAML. Discourse non supporta un file Compose scritto autonomamente e il container non deve essere suddiviso manualmente. Se sei abituato a eseguire servizi su un VPS con Docker Compose, troverai un'architettura diversa. Qui non esiste docker compose up -d e ./launcher rebuild app è il deploy.

Cosa serve a Discourse prima di iniziare

Quattro requisiti causano problemi, e ciascuno può bloccare l'installazione prima di raggiungere la pagina di accesso.

  • Memoria. Un container esegue PostgreSQL, Redis, Sidekiq e un server Web Ruby. La fase di build compila gli asset e richiede più memoria del sito in esecuzione.
  • Un nome di dominio reale. La configurazione di esempio fornita con il software lo dichiara chiaramente: "Discourse non funziona con un semplice indirizzo IP."
  • Un percorso per la posta in uscita. L'attivazione degli account, il ripristino delle password, gli inviti degli amministratori e le email di riepilogo vengono inviati tramite SMTP (simple mail transfer protocol).
  • Le porte 80 e 443 libere sull'host, a meno che Discourse non venga spostato intenzionalmente dietro un proxy già in esecuzione.
ChartDiscourse published hardware requirements (official install docs, August 2026)
The data behind this chart
[
  {
    "label": "Documented minimum",
    "ram_gb": 1,
    "storage_gb": 10
  },
  {
    "label": "Documented recommended",
    "ram_gb": 2,
    "storage_gb": 20
  }
]

Il documento ufficiale di installazione indica come requisito minimo 1 GB di RAM con swap e 10 GB di spazio su disco, e raccomanda 2 GB di RAM con 20 GB di spazio su disco. Interpreta la prima riga come il valore che consente di completare l'installazione, non come il valore necessario per gestire una community. La differenza è importante perché il picco di memoria si verifica durante la build, non a causa del traffico.

Imposta il dominio sul server prima dell'installazione

Crea un record A per il nome host che utilizzerai, quindi verificalo direttamente dal server.

dig +short forum.example.com
curl -4 -s https://ifconfig.co

Entrambi i comandi devono restituire lo stesso indirizzo. Devono corrispondere perché la procedura guidata di configurazione esegue un test di connessione sul nome host. Un record che punta ancora altrove non supera il test. Inoltre, un record creato due minuti fa potrebbe essere ancora memorizzato nella cache. Attendi quindi la scadenza del vecchio TTL (time to live), invece di forzare la procedura guidata.

Decidi ora se il record sarà sottoposto a proxy da una CDN. Un record sottoposto a proxy nasconde l'indirizzo del server. La richiesta del certificato del container fallisce perché la challenge ACME (automatic certificate management environment) riceve risposta dal proxy invece che da Discourse. Per la prima installazione, mantieni il record senza proxy.

Eseguire l'installer ufficiale

Un comando installa git, installa Docker con lo script di installazione ufficiale di Docker, clona discourse_docker in /var/discourse e avvia la procedura guidata di configurazione.

wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bash

Se Docker è già installato sul server e si preferisce esaminare ogni passaggio, eseguire manualmente le stesse operazioni.

sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setup

Eseguire il comando come root. Se viene avviato da un utente ordinario, discourse-setup si interrompe subito con This script must be run as root. Please sudo or log in as root first.. Se Docker non è installato sul server, si interrompe con Docker is not installed. Please install Docker first., perché la clonazione manuale non installa alcun componente.

Cosa chiede la procedura guidata e cosa scrive

Ad agosto 2026 discourse-setup è un wrapper sottile. Esegue discourse/setup-wizard:release in un container con la rete dell'host e il socket Docker montato, in modo che la procedura guidata possa analizzare la macchina che sta configurando. Chiede il nome host e gli indirizzi email degli amministratori, quindi i parametri SMTP. Scrive containers/app.yml, quindi esegue nuovamente la build.

Prima di iniziare è utile conoscere due comportamenti. Se la macchina ha poca memoria e non dispone di swap, la procedura guidata si arresta e propone di crearla: il wrapper crea quindi un /swapfile da 2 GB, lo aggiunge a /etc/fstab, imposta vm.swappiness = 10 in /etc/sysctl.d/30-discourse-swap.conf e riavvia la procedura guidata. Al termine, la procedura guidata stampa Rebuilding app in 5 seconds (Ctrl+C to cancel)... ed esegue ./launcher rebuild app sull'host. Questa build richiede diversi minuti su un VPS di piccole dimensioni. La prima è la più lenta perché ogni asset viene compilato da zero.

./discourse-setup --help elenca i flag da controllare quando si verifica un problema. --skip-rebuild scrive la configurazione senza eseguire la build, mentre --skip-connection-test ignora i controlli DNS e delle porte. Usa --skip-connection-test solo quando sai già perché il test non riesce, ad esempio quando l'host si trova dietro un firewall di rete che controlli direttamente.

Leggi app.yml prima della prima ricostruzione

La procedura guidata scrive un file che ora devi gestire direttamente. Aprilo con sudo nano /var/discourse/containers/app.yml. Queste sono le parti che determinano quasi tutto.

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  ## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

expose:
  - "80:80"   # http
  - "443:443" # https

env:
  DISCOURSE_HOSTNAME: "forum.example.com"
  DISCOURSE_DEVELOPER_EMAILS: "you@example.com"
  DISCOURSE_SMTP_ADDRESS: smtp.example.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: user@example.com
  DISCOURSE_SMTP_PASSWORD: "your-smtp-password"

DISCOURSE_HOSTNAME è l'indirizzo a cui il sito risponde e Discourse lo usa per generare i collegamenti. Un valore errato fa sì che il sito si carichi una volta e poi reindirizzi altrove. DISCOURSE_DEVELOPER_EMAILS è un elenco separato da virgole. Gli indirizzi indicati diventano automaticamente amministratori al primo signup. Inserisci il tuo indirizzo e registrati usando quello, perché è così che viene creato il primo account amministratore.

Il file contiene la password SMTP in testo in chiaro. Limita quindi l'accesso alla directory con sudo chmod 700 /var/discourse/containers. Il formato è inoltre YAML, quindi gli spazi bianchi fanno parte della configurazione. Una chiave non allineata correttamente interrompe la build con un errore di analisi e lascia il sito non disponibile. Un problema è documentato nel file di esempio stesso. Un # inserito in una password non racchiusa tra virgolette avvia un commento. Racchiudi quindi tra virgolette qualsiasi password che lo contenga.

L’email è il passaggio che blocca la maggior parte delle installazioni

Ad agosto 2026 la procedura guidata consente di ignorare la configurazione SMTP e usare invece gli accessi Discourse ID. Anche app.yml include un’opzione DISCOURSE_SKIP_EMAIL_SETUP corrispondente, descritta come esclusione della convalida della configurazione email. Ignorare questo passaggio è ragionevole per una prima valutazione del software. È una scelta inadatta per una community, perché senza posta in uscita nessuno può attivare un account o reimpostare una password.

Il problema pratico è che la maggior parte dei provider VPS blocca la porta 25 in uscita. Un mail server semplice installato sul server, quindi, non riuscirà a consegnare i messaggi. Usa un relay autenticato sulla porta 587 oppure sulla porta 465 con TLS implicito (Transport Layer Security). Per la porta 465, imposta DISCOURSE_SMTP_FORCE_TLS: true, come raccomandato dalla configurazione di esempio per questa porta. Verifica la raggiungibilità dall’host prima di ricreare il container.

nc -vz smtp.example.com 587

Un risultato corretto è una singola riga che termina con succeeded!. Se il comando resta in attesa e poi va in timeout, significa che la porta è bloccata lungo il percorso in uscita dal VPS. Nessuna impostazione di Discourse può risolvere questo problema. Usa una porta consentita dal provider oppure chiedi al provider di aprirla.

Quando il sito è operativo, invia un messaggio di test dalla pagina Email nell’area Admin. Controlla quindi le schede Skipped e Bounced nella stessa pagina. In queste schede Discourse registra i messaggi che ha rifiutato di inviare e quelli rifiutati dal relay. Viene indicata anche la causa, quindi il controllo è più rapido della lettura dei log.

TLS: lasciare che il container ottenga il proprio certificato

Se Discourse gestisce le porte 80 e 443, utilizzate il meccanismo integrato per il rilascio dei certificati. Decommentate le due righe del template SSL mostrate sopra, quindi ricreate il container. Il template configura acme.sh, salva i certificati nel volume condiviso in /shared/ssl, li rinnova secondo una pianificazione interna al container e imposta Discourse per forzare HTTPS.

La porta 80 deve rimanere raggiungibile da Internet, perché la challenge HTTP riceve risposta su quella porta. Un firewall che consente soltanto la porta 443 permette di completare la build, ma il certificato non verrà mai rilasciato. Verificate il risultato con ./launcher logs app subito dopo la ricreazione.

Conviene mettere nginx o Caddy davanti?

Se Discourse è l'unico servizio web sul VPS, no. Il container esegue già un nginx ottimizzato. Un secondo proxy aggiunge un hop, un altro certificato da rinnovare e una nuova possibile fonte di problemi con gli header.

Usa un proxy davanti al container quando lo stesso VPS ospita altri siti. Aggiungi templates/web.socketed.template.yml all'elenco dei template, commenta entrambe le righe expose e lascia commentati i due template SSL. Il container resterà in ascolto su un socket Unix in /var/discourse/shared/standalone/nginx.http.sock e non occuperà alcuna porta. In questo modo le porte 80 e 443 restano disponibili per il tuo proxy.

server {
  listen 443 ssl;
  server_name forum.example.com;

  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 $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

I due punti finali dopo .sock fanno parte della sintassi nginx per i socket Unix. sudo nginx -t rifiuta la configurazione se mancano. Anche X-Forwarded-Proto è obbligatorio. Discourse genera link assoluti. Senza quell'header, su una pagina HTTPS genera link http:// e i browser li bloccano come contenuto misto. Quando il container usa un socket, la gestione di TLS spetta a te. Emetti quindi il certificato sull'host con Certbot su Ubuntu 24.04 e nginx. Se non hai ancora scelto un proxy, il confronto tra nginx, Caddy e Traefik illustra i compromessi della scelta.

Ricostruzioni, aggiornamenti e comandi che userai effettivamente

cd /var/discourse
./launcher rebuild app

rebuild elimina il container in esecuzione, ne prepara uno nuovo da app.yml e lo avvia. Il sito resta offline per l'intera durata della build, quindi considera ogni modifica alla configurazione come un'interruzione programmata di alcuni minuti.

Le modifiche ai soli valori in env: non richiedono questa procedura. ./launcher destroy app && ./launcher start app ricrea il container dall'immagine già compilata e richiede pochi secondi. Qualsiasi modifica in templates: o hooks: cambia l'immagine stessa, quindi richiede la ricostruzione completa.

Gli aggiornamenti arrivano in due modi. Gli aggiornamenti minori vengono applicati dall'interfaccia web in /admin/upgrade, tramite il plugin docker_manager che app.yml clona durante la build. Le modifiche all'immagine di base o ai template provengono da git.

cd /var/discourse
git pull
./launcher rebuild app

Le ricostruzioni sono il punto in cui i server di piccole dimensioni possono andare in errore, perché la compilazione degli asset raggiunge il picco di utilizzo della memoria dell'intero sistema. Se una build si interrompe a metà e dmesg mostra una riga come Out of memory: Killed process che indica un processo ruby, durante la build si è esaurita la memoria, anche se il sito funzionava correttamente prima. Aggiungi lo swap ed esegui di nuovo la ricostruzione.

./launcher logs app
./launcher enter app
./launcher cleanup

logs visualizza l'output del container, enter apre una shell al suo interno e cleanup rimuove i container arrestati da più di 24 ore. Esegui cleanup periodicamente, perché ogni ricostruzione lascia un vecchio container e lo spazio su disco di un VPS di piccole dimensioni si esaurisce senza segnali evidenti.

Backup e file escluso dal backup

Esegui i backup dalla pagina Backups in Admin. L'archivio viene salvato sull'host in /var/discourse/shared/standalone/backups/default/. Lo stesso processo può essere eseguito da una shell.

cd /var/discourse
./launcher enter app
discourse backup

discourse restore <filename> annulla l'operazione e i ripristini vengono rifiutati finché non esegui discourse enable_restore. Questa protezione impedisce a un comando eseguito per errore di sovrascrivere un forum attivo.

Devi colmare personalmente due lacune. L'archivio contiene il database e include i file caricati solo quando è attiva l'impostazione di backup che include gli upload. Controlla quindi questa impostazione prima di considerare affidabile il backup. L'archivio non contiene mai app.yml. Per questo, anche un ripristino su un VPS nuovo richiede il nome host e il blocco SMTP. Devi quindi copiare anche questo file fuori dal server.

Inoltre, l'archivio si trova sullo stesso disco del sito che dovrebbe proteggere. Questo non è un backup. Copialo periodicamente in un'altra posizione.

rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/

Quanto costa in RAM un forum molto attivo

Il bootstrap imposta UNICORN_WORKERS e db_shared_buffers in base alla memoria e alla CPU rilevate; la configurazione di esempio limita i buffer condivisi a un quarto della memoria totale. Ogni worker Unicorn è un processo Ruby completo e Sidekiq esegue i job in background insieme a questi processi. Di conseguenza, l'uso della memoria dipende dalle richieste simultanee, non dal numero di utenti registrati. Un forum poco attivo con alcune centinaia di utenti non costituisce un carico elevato. Di solito conta di più ciò che condivide il server. Se si tratta di una libreria fotografica, i valori minimi di RAM misurati in confronto tra PhotoPrism e Immich indicano se una ricostruzione di Discourse dispone ancora di memoria sufficiente per terminare.

Non dimensionare il server in base a un numero riportato in un articolo, incluso questo. Misura il tuo ambiente.

free -m
docker stats --no-stream

L'uso costante della swap insieme a pagine lente indica che la RAM è insufficiente. Se la memoria resta stabile mentre le pagine sono lente, la causa è probabilmente diversa. Leggi ./launcher logs app prima di acquistare un piano più grande. Aggiungi anche un controllo dall'esterno del server, perché un forum che esaurisce la memoria alle 3:00 può smettere di funzionare senza segnalarlo: un monitor di stato Uptime Kuma self-hosted su un host separato ti avvisa prima degli utenti.

Quando Discourse è la scelta sbagliata

Discourse è un'applicazione di grandi dimensioni, con un'installazione pesante e un ciclo di rebuild per ogni impostazione contenuta in app.yml. Questo costo offre strumenti di moderazione completi e una ricerca che continua a funzionare anche quando l'archivio è voluminoso. Per trenta persone che cercano semplicemente uno spazio in cui parlare, richiede più risorse di quanto la conversazione necessiti. Leggi prima il confronto tra i software per forum self-hosted e scegli Discourse perché ti servono le funzionalità che offre, non perché è il nome che già conoscevi.

FAQ

Posso installare Discourse su un VPS senza un nome di dominio?

No. La configurazione fornita specifica che Discourse non funziona con un semplice indirizzo IP e che è richiesto DISCOURSE_HOSTNAME. Discourse costruisce link assoluti a partire da questo hostname, quindi un indirizzo IP al suo posto rompe i link e impedisce l'emissione del certificato. Crea un record A prima di iniziare e verifica con dig +short forum.example.com che risolva all'indirizzo del server.

Devo configurare SMTP per completare l'installazione?

A partire da agosto 2026 puoi saltare questo passaggio. La procedura guidata di configurazione offre invece l'accesso tramite Discourse ID e app.yml include un'opzione per ignorare la convalida della configurazione email. Per qualsiasi utilizzo oltre una prima prova, configuralo: sia l'attivazione degli account sia il ripristino delle password avvengono tramite email. Usa un relay autenticato sulla porta 587 o 465, perché la maggior parte dei provider VPS blocca la porta 25 in uscita.

Perché la ricostruzione di Discourse si è interrotta?

La causa più comune è la memoria. La compilazione degli asset durante la build richiede più memoria del sito in esecuzione, quindi un server che gestisce correttamente il forum può comunque non riuscire a ricostruirlo. Se dmesg mostra Out of memory: Killed process con un processo Ruby, aggiungi swap (il file di swap creato dalla procedura guidata ha dimensione 2 GB) ed esegui di nuovo ./launcher rebuild app. Se la build si interrompe a causa di un errore YAML, il problema è invece probabilmente un'indentazione errata in app.yml.

Discourse deve essere eseguito dietro il mio nginx o Caddy?

Solo se il VPS ospita anche altri siti. Se il server esegue soltanto Discourse, lascia che il container mantenga le porte 80 e 443 e rilasci il proprio certificato: in questo modo ci sono meno componenti da gestire. Per condividere la macchina, aggiungi templates/web.socketed.template.yml, commenta le righe expose e inoltra le richieste al socket Unix in /var/discourse/shared/standalone/nginx.http.sock. Inoltra anche X-Forwarded-Proto, altrimenti Discourse genera link http:// in una pagina HTTPS.

Come posso eseguire il backup di un'installazione self-hosted di Discourse?

Usa la pagina Backups nell'area Admin oppure esegui discourse backup dopo ./launcher enter app. Gli archivi vengono salvati sull'host in /var/discourse/shared/standalone/backups/default/. Verifica che sia attiva l'impostazione che include gli upload, copia /var/discourse/containers/app.yml insieme all'archivio e trasferisci entrambi su un'altra macchina, perché un backup sullo stesso disco del sito non sopravvive al guasto da cui dovrebbe proteggerti.