1 12/04/2026 8 min

Installare Ghost su Ubuntu 22.04: scelta dell’architettura

Ghost funziona bene su Ubuntu 22.04 LTS se lo tratti come un servizio applicativo serio, non come un pacchetto “da cliccare e via”. La strada pulita è: utente dedicato, database separato, reverse proxy Nginx, TLS attivo, backup dei file e del database, permessi stretti. Se salti uno di questi punti, il nodo non è Ghost: è l’operatività che diventa fragile.

Qui l’obiettivo è un’installazione ripetibile e leggibile, adatta a un server singolo. Se ti serve alta disponibilità, storage condiviso o replica database, il disegno cambia e va impostato prima, non dopo il deploy.

Prerequisiti minimi e verifica dello stato del server

Prima di toccare Ghost verifica che il sistema sia aggiornato, che il nome host punti al server giusto e che la porta 80/443 sia raggiungibile dall’esterno. Senza questa base, qualsiasi problema di setup si confonde con DNS, firewall o proxy.

Controlli rapidi utili:

lsb_release -a
hostnamectl
ip a
ss -lntp | egrep ':(80|443|3306)\b'
systemctl status ssh --no-pager

Se il server è appena nato, aggiorna subito il sistema e installa gli strumenti base. Su Ubuntu 22.04 conviene anche abilitare gli aggiornamenti di sicurezza automatici, almeno per il profilo LTS.

sudo apt update
sudo apt -y upgrade
sudo apt -y install curl wget unzip gnupg ca-certificates ufw

Stack consigliato: Nginx, MySQL e Node.js LTS

Ghost richiede Node.js recente e si integra bene con MySQL 8.0 o MariaDB compatibile, anche se su Ubuntu 22.04 la scelta più lineare è MySQL. Nginx fa da reverse proxy e termina TLS. Questa combinazione è semplice da leggere nei log e da gestire nei backup.

La versione di Node va allineata a quella supportata dalla release di Ghost che intendi installare. Non dare per scontato che “ultima LTS” significhi sempre compatibilità totale: controlla la matrice ufficiale della release e chiudi il gap installando la versione richiesta, non quella più comoda.

1. Creare utente e directory di lavoro

Evita di eseguire Ghost come root. Usa un utente dedicato, con home propria e permessi limitati alla directory del sito.

sudo adduser ghostuser
sudo mkdir -p /var/www/ghost
sudo chown ghostuser:ghostuser /var/www/ghost

Questo riduce il blast radius: se un plugin o una dipendenza si rompe, l’impatto resta confinato al servizio applicativo. Il rollback qui è banale: rimuovere la directory e l’utente dedicato se sei ancora in fase di prova.

2. Installare Nginx e aprire il firewall

Nginx serve sia come front-end HTTP sia come punto di controllo per il TLS. Prima di configurarlo, abilita il firewall in modo coerente con il servizio che esporrai.

sudo apt -y install nginx
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verbose

Il controllo minimo è che le porte 80 e 443 risultino ammesse e che Nginx sia in ascolto. Se UFW è già gestito da policy aziendali, non duplicare regole a caso: allineati alla catena esistente.

3. Installare MySQL e preparare il database

Ghost usa un database per contenuti, utenti e configurazione applicativa. Il database va creato con un utente dedicato e privilegi minimi, non con account amministrativi riutilizzati.

sudo apt -y install mysql-server
sudo systemctl enable --now mysql
sudo mysql_secure_installation

Entra in MySQL e crea database e utente. Sostituisci la password con una stringa forte generata fuori banda e poi conservata in un password manager; non lasciarla in chiaro nei ticket o nei file condivisi.

sudo mysql
CREATE DATABASE ghostdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'ghostuser'@'localhost' IDENTIFIED BY 'PASSWORD_FORTE';
GRANT ALL PRIVILEGES ON ghostdb.* TO 'ghostuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Verifica subito che l’utente possa autenticarsi e che il database risponda. Se questo passaggio fallisce, non andare avanti con Ghost: hai un problema di credenziali o di permessi, non di CMS.

4. Installare Node.js e Ghost-CLI

Ghost-CLI automatizza gran parte del setup, ma resta sensibile alla versione di Node. Sul server conviene installare una release supportata e poi il tool CLI globale per l’utente dedicato.

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt -y install nodejs
node -v
npm -v
sudo npm install -g ghost-cli@latest

Se la tua release di Ghost richiede una versione diversa di Node, cambia il ramo del repository in modo esplicito. Il falso positivo tipico è “installazione riuscita ma avvio KO” per incompatibilità runtime: lo vedi dai log di `ghost log` o da `systemctl status`.

5. Installare Ghost nella directory finale

Entra come utente dedicato e lancia l’installer nella directory corretta. Qui Ghost-CLI chiede nome dominio, configurazione del database, utente admin iniziale e setup di Nginx.

sudo -iu ghostuser
cd /var/www/ghost
ghost install

Durante la procedura verifica con attenzione i campi che finiscono in URL pubblici e quelli che definiscono il database. Un errore nel dominio si riflette poi in redirect sbagliati, cookie non validi o link interni rotti.

Se preferisci un’installazione non interattiva, Ghost-CLI supporta parametri e file di configurazione, ma per un primo deploy conviene passare dalla procedura guidata. Il vantaggio è che i controlli di validazione intercettano subito dipendenze mancanti e permessi errati.

6. Configurare il file `config.production.json`

La configurazione effettiva di Ghost vive nel file di produzione, normalmente in `/var/www/ghost/config.production.json`. Qui definisci URL pubblico, bind locale e parametri del database. Non modificare alla cieca: fai prima una copia di backup.

cp /var/www/ghost/config.production.json /var/www/ghost/config.production.json.bak

Esempio essenziale:

{
  "url": "https://blog.example.com",
  "server": {
    "host": "127.0.0.1",
    "port": 2368
  },
  "database": {
    "client": "mysql",
    "connection": {
      "host": "127.0.0.1",
      "user": "ghostuser",
      "password": "PASSWORD_FORTE",
      "database": "ghostdb",
      "charset": "utf8mb4"
    }
  }
}

Se il server è dietro proxy o CDN, l’URL deve essere coerente con quello realmente pubblicato verso il client. In caso contrario Ghost genera link errati e il login può diventare instabile per mismatch tra schema, host e cookie.

7. Configurare Nginx come reverse proxy

Ghost non va esposto direttamente su Internet sulla porta applicativa. Nginx deve ricevere le richieste esterne e inoltrarle a `127.0.0.1:2368`.

sudo nano /etc/nginx/sites-available/ghost

Snippet essenziale:

server {
    listen 80;
    server_name blog.example.com;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:2368;
    }
}

Abilita il sito e testa la sintassi prima del reload. Qui il rollback è immediato: disabiliti il symlink del virtual host e ricarichi Nginx se la configurazione nuova crea problemi.

sudo ln -s /etc/nginx/sites-available/ghost /etc/nginx/sites-enabled/ghost
sudo nginx -t
sudo systemctl reload nginx

8. Abilitare HTTPS con Let’s Encrypt

In produzione il certificato TLS non è opzionale. La parte importante non è solo emetterlo, ma far sì che il redirect HTTP→HTTPS sia coerente con l’URL configurato in Ghost e con il server_name di Nginx.

sudo apt -y install certbot python3-certbot-nginx
sudo certbot --nginx -d blog.example.com

Dopo il rilascio controlla la scadenza automatica e il rinnovo. Un certificato valido oggi non serve a nulla se non hai verificato il timer di renew e la risposta del server al reload.

systemctl list-timers | grep certbot
sudo certbot renew --dry-run

9. Primo accesso e hardening minimo dell’istanza

Terminato il setup, apri il dominio nel browser e completa la creazione dell’account amministratore se non l’hai già fatto nel wizard. Poi riduci la superficie esposta: niente porte applicative pubbliche, niente database in ascolto su tutte le interfacce, niente utenti condivisi.

Controlli utili:

sudo ss -lntp | egrep ':(80|443|2368|3306)\b'
sudo systemctl status ghost_*.service --no-pager
sudo tail -n 50 /var/www/ghost/content/logs/ghost.log

Se MySQL è esposto fuori dal loopback, correggi subito. Se Ghost ascolta direttamente su 0.0.0.0 invece che su `127.0.0.1`, stai allargando inutilmente il perimetro d’attacco.

Backup, manutenzione e ripristino

Una installazione fatta bene è una installazione che sai ripristinare. Per Ghost servono almeno due elementi: dump del database e copia della directory `content/`, dove stanno temi, upload e asset. Senza questi due pezzi il restore è parziale.

mysqldump -u ghostuser -p ghostdb > ghostdb.sql
rsync -a /var/www/ghost/content/ /backup/ghost/content/

Per il ripristino, l’ordine corretto è database prima, file poi, quindi restart del servizio. Se inverti i passaggi rischi di avviare l’app con dati mancanti o riferimenti a media non ancora presenti.

Problemi tipici e come leggerli senza perdere tempo

Se il sito mostra errore 502, il layer da guardare per primo è Nginx verso Ghost: servizio fermo, porta sbagliata, permessi o crash all’avvio. Se la pagina è bianca dopo il login, controlla i log applicativi e la coerenza dell’URL pubblico. Se il database non risponde, Ghost spesso non parte proprio e il problema si vede subito nel servizio systemd.

Ordine pratico di verifica:

curl -I https://blog.example.com
sudo journalctl -u nginx -n 50 --no-pager
sudo journalctl -u ghost_*.service -n 50 --no-pager
sudo tail -n 100 /var/www/ghost/content/logs/ghost.log

Se il problema è dopo un cambio di configurazione, torna al backup del file modificato prima di fare altre ipotesi. In genere è più veloce ripristinare uno snippet noto buono che inseguire sintomi secondari.

Schema operativo che regge nel tempo

La differenza tra una demo e un’installazione gestibile sta nei dettagli operativi: utente dedicato, servizi separati, log consultabili, backup testati, TLS valido e configurazione versionata. Ghost non chiede infrastrutture complesse, ma pretende disciplina. Se la appoggi su un server “arrangiato”, il problema emergerà al primo aggiornamento, al primo rinnovo certificato o al primo restore.

Se devi portarla in produzione vera, aggiungi monitoraggio su uptime HTTP, consumo RAM, spazio disco di `/var/lib/mysql` e integrità del processo Ghost. La metrica minima da osservare è il tasso di errori 5xx e il tempo di risposta del front-end: se peggiora dopo un deploy, hai almeno un segnale per tornare indietro senza discutere per ore.