1 20/04/2026 13 min

Scelta dell’architettura prima di toccare il server

SonarQube non va trattato come un servizio “leggero” da installare e dimenticare. Su Ubuntu 20.04 LTS la differenza tra un’installazione pulita e una che poi degrada dopo pochi giorni sta quasi sempre in tre punti: JVM corretta, database esterno affidabile e limiti di sistema adeguati. Se questi tre elementi sono impostati male, l’interfaccia sale lo stesso, ma poi compaiono errori di indexing, timeout o blocchi all’avvio.

La scelta più sensata in produzione è usare PostgreSQL separato e non il database embedded. Per un server singolo va bene anche una VM piccola, ma non bisogna confondere “funziona” con “è stabile”. Il vero obiettivo è avere una macchina con memoria sufficiente, swap presente ma non usato come stampella, e un servizio systemd che riparta in modo prevedibile dopo reboot o crash.

Qui sotto trovi una procedura completa per Ubuntu 20.04 LTS Server, con passaggi reversibili e verifiche pratiche. Dove serve, il focus è su ciò che conviene controllare subito per evitare di arrivare a un SonarQube formalmente avviato ma inutilizzabile sotto carico minimo.

Prerequisiti minimi e dimensionamento realistico

Per un’istanza piccola ma seria, considera almeno 4 vCPU, 8 GB di RAM e 20-30 GB liberi su disco, meglio se su volume separato. SonarQube usa Elasticsearch internamente e soffre quando la memoria è stretta o il filesystem è lento. Se il server deve ospitare anche altri servizi, separare i carichi è più prudente che “ottimizzare dopo”.

Serve Java supportato dalla versione di SonarQube che vuoi installare. Per molte versioni recenti la strada corretta è Java 17. Non conviene installare una JRE a caso e sperare che basti: verifica sempre la matrice di compatibilità della release specifica. Se non la hai sotto mano, chiudi il gap consultando la documentazione ufficiale della tua versione prima di procedere.

Per il database, PostgreSQL è la scelta standard. MySQL/MariaDB non sono la via consigliata per SonarQube moderno. Se stai migrando da un’istanza vecchia, non improvvisare con dump e restore senza prima verificare la compatibilità dello schema e della release di destinazione.

Aggiornamento base del sistema e pacchetti necessari

Parti dal sistema pulito e aggiornato. Questo riduce problemi banali come librerie mancanti, limiti kernel obsoleti o repository non sincronizzati.

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

Dopo l’aggiornamento, verifica la versione del kernel e dello spazio libero. Non è un formalismo: se il disco è già vicino al limite, SonarQube può avviarsi e poi fallire durante l’indicizzazione o i log possono saturare il filesystem.

uname -r
df -h /
free -h

Se la memoria disponibile è poca, non forzare l’installazione sperando che il sistema “tenga”. SonarQube ha bisogno di RAM reale, non solo di swap. Lo swap aiuta a evitare crash immediati, ma non sostituisce il dimensionamento.

Creazione dell’utente dedicato e preparazione delle directory

SonarQube non va eseguito come root. L’utente dedicato riduce il raggio d’impatto di un errore e ti permette di separare meglio file applicativi, log e dati. Se più avanti devi fare troubleshooting, sapere cosa appartiene a quale utente evita confusione.

sudo useradd --system --create-home --shell /bin/bash sonar
sudo mkdir -p /opt/sonarqube
sudo mkdir -p /var/sonarqube
sudo chown -R sonar:sonar /opt/sonarqube /var/sonarqube

La directory applicativa tipica è `/opt/sonarqube`. I dati e i log possono restare nello stesso albero, ma tenere separato almeno il volume dati è una scelta più pulita se hai storage dedicato. In ogni caso, il proprietario deve essere coerente con l’utente di esecuzione.

Installazione di Java 17 su Ubuntu 20.04 LTS

Su Ubuntu 20.04 la via più semplice è il pacchetto OpenJDK dai repository ufficiali. Se la tua versione di SonarQube richiede una minor release specifica, adegua il pacchetto in base a quella richiesta, ma non mischiare runtime diversi senza motivo.

sudo apt -y install openjdk-17-jre-headless
java -version

L’output atteso deve mostrare Java 17. Se compare una versione diversa, non andare avanti: SonarQube potrebbe comunque partire, ma poi bloccarsi con errori poco chiari o comportamento non supportato.

Se il server ha più runtime installati, controlla quale Java viene risolto dal sistema. Questo è un punto classico di errore quando si lavora su macchine usate anche per altri stack.

update-alternatives --config java

PostgreSQL: database e utente separati

Il database non va creato “al volo” dentro un cluster condiviso senza permessi chiari. Crea un database dedicato, un utente dedicato e una password robusta. Non scrivere la password in chiaro nei comandi storici della shell se puoi evitarlo; usa un prompt interattivo o un file protetto temporaneamente.

sudo apt -y install postgresql postgresql-contrib
sudo -u postgres psql

Dentro `psql`, crea utente e database. Sostituisci `SONAR_PASSWORD` con una password generata e poi redatta nei documenti operativi.

CREATE USER sonar WITH ENCRYPTED PASSWORD 'SONAR_PASSWORD';
CREATE DATABASE sonarqube OWNER sonar ENCODING 'UTF8';
GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonar;

Esci e verifica che il database esista davvero. Questo controllo evita di scoprire l’errore solo al primo avvio del servizio.

sudo -u postgres psql -lqt | cut -d \| -f 1 | sed 's/ //g' | grep '^sonarqube$'

Se il server PostgreSQL è remoto, chiudi il gap verificando anche `pg_hba.conf`, firewall e reachability TCP sulla porta 5432. In quel caso il database può esistere ma restare irraggiungibile dall’applicazione.

Download e posizionamento di SonarQube

Scarica sempre la release che hai deciso di supportare, senza saltare tra versioni diverse durante i test. È uno dei modi più rapidi per perdere tempo con differenze di compatibilità che non c’entrano nulla con il tuo server.

cd /tmp
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-10.6.0.92116.zip
sudo unzip sonarqube-10.6.0.92116.zip -d /opt
sudo mv /opt/sonarqube-10.6.0.92116 /opt/sonarqube
sudo chown -R sonar:sonar /opt/sonarqube

Dopo l’estrazione, controlla che la directory contenga i file attesi: `bin`, `conf`, `lib`, `logs`, `extensions`. Se la struttura non coincide, hai scaricato o estratto male il pacchetto e conviene fermarsi subito.

ls -la /opt/sonarqube

Configurazione del database e della directory dati

Il file centrale è ` /opt/sonarqube/conf/sonar.properties`. Qui si definiscono database, porta HTTP e alcune impostazioni operative. Prima di modificarlo, fai una copia di backup: è una modifica reversibile e non costa nulla.

sudo cp /opt/sonarqube/conf/sonar.properties /opt/sonarqube/conf/sonar.properties.bak

Apri il file e imposta almeno i parametri del database. Se vuoi usare una porta HTTP non standard, fallo qui, ma tieni presente che un reverse proxy davanti resta la soluzione più pulita in ambienti esposti.

sonar.jdbc.username=sonar
sonar.jdbc.password=SONAR_PASSWORD
sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube
sonar.web.port=9000

Se PostgreSQL è su host diverso, sostituisci `localhost` con il nome o l’IP corretto. Quando fai questo cambio, verifica anche la latenza e l’accesso di rete: un database remoto lento si traduce in una UI che sembra “aprirsi” ma poi rimane inutilizzabile.

Limiti kernel e tuning richiesti da Elasticsearch interno

SonarQube include componenti basati su Elasticsearch, quindi alcuni parametri kernel sono obbligatori. Il classico errore di chi installa in fretta è ignorare i limiti di file descriptor e i `vm.max_map_count`. Il servizio può partire, ma poi la parte di search/indexing fallisce.

Aggiungi una configurazione dedicata in `/etc/sysctl.d/99-sonarqube.conf`.

sudo tee /etc/sysctl.d/99-sonarqube.conf > /dev/null <<'EOF'
vm.max_map_count=524288
fs.file-max=131072
EOF
sudo sysctl --system

Verifica il valore applicato. Se non coincide, non andare oltre: è una causa frequente di fallimento all’avvio.

sysctl vm.max_map_count
sysctl fs.file-max

Serve anche un limite alto per gli open file. Con systemd è più pulito impostarlo nel service unit, non con workaround sparsi. L’obiettivo è evitare che il processo venga strozzato da limiti ereditati dalla sessione shell.

Unit systemd per avvio controllato

Creare un’unità systemd è preferibile rispetto all’avvio manuale da shell. Così ottieni restart automatico, log centralizzati e un punto unico di controllo. Prima di scrivere il servizio, tieni presente che il processo va eseguito come utente `sonar` e che la directory di lavoro deve essere corretta.

sudo tee /etc/systemd/system/sonarqube.service > /dev/null <<'EOF'
[Unit]
Description=SonarQube service
After=network.target postgresql.service

[Service]
Type=forking
ExecStart=/opt/sonarqube/bin/linux-x86-64/sonar.sh start
ExecStop=/opt/sonarqube/bin/linux-x86-64/sonar.sh stop
User=sonar
Group=sonar
Restart=always
LimitNOFILE=131072
LimitNPROC=8192
TimeoutStartSec=5min

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable sonarqube

Dopo la creazione dell’unità, controlla il file generato e la sintassi del servizio. Se c’è un errore di path o permessi, scoprirlo adesso è molto meglio che farlo emergere come avvio fallito in produzione.

systemctl cat sonarqube
systemctl status sonarqube --no-pager

Se il servizio non parte, i log vanno letti subito con `journalctl -u sonarqube -b`. È il modo più rapido per capire se il problema è Java, database, permessi o tuning di sistema.

Avvio iniziale e verifica dei log

Una volta predisposto tutto, avvia il servizio e guarda i log in tempo reale. L’avvio iniziale può richiedere qualche minuto, soprattutto se il database è nuovo o se il server ha risorse modeste.

sudo systemctl start sonarqube
sudo journalctl -u sonarqube -f

I segnali di buon esito sono chiari: niente stack trace ripetuti, niente errori di connessione al database e, dopo l’avvio, ascolto sulla porta 9000. Puoi verificare con `ss` o `curl` locale.

ss -lntp | grep ':9000'
curl -I http://127.0.0.1:9000

Se `curl` restituisce `HTTP/1.1 200 OK` o un redirect coerente, il servizio web è vivo. Se invece ottieni `connection refused`, il problema è ancora nel processo o nel bind dell’interfaccia. Se ricevi timeout, guarda prima firewall e binding su `localhost` o su un IP specifico.

Accesso web, primo login e hardening minimo

Il primo accesso avviene di norma su `http://IP_DEL_SERVER:9000`. Le credenziali iniziali standard sono spesso `admin` / `admin`, ma vanno cambiate immediatamente al primo login. Non lasciarle mai in uso, nemmeno in ambienti di test esposti a una rete condivisa.

Appena dentro, verifica la versione installata e lo stato del server dalla UI. Se il dashboard segnala problemi di background task o di database, non ignorarli: spesso sono il primo campanello di allarme per limiti RAM o tuning non corretto.

Per un’esposizione più pulita, conviene mettere SonarQube dietro Nginx o Apache con TLS. In quel caso, lascia il backend in ascolto su localhost e pubblica solo il reverse proxy. Riduci così la superficie d’attacco e semplifichi la gestione del certificato.

Reverse proxy con Nginx: schema consigliato

Se vuoi pubblicarlo in modo ordinato, Nginx davanti è una scelta pratica. Il proxy deve inoltrare header corretti e supportare connessioni lunghe. La parte più fragile di queste configurazioni è quasi sempre il timeout o il mancato passaggio di `X-Forwarded-Proto`.

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

    location / {
        proxy_pass http://127.0.0.1:9000;
        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_http_version 1.1;
        proxy_read_timeout 300;
        proxy_connect_timeout 60;
    }
}

Dopo il reload di Nginx, testa la risposta e controlla i log del proxy. Se il backend risponde ma il browser mostra errori strani, spesso il problema è lì, non in SonarQube.

sudo nginx -t
sudo systemctl reload nginx
curl -I http://sonar.example.com

TLS e pubblicazione sicura

La pubblicazione in chiaro non è una buona idea se l’istanza è accessibile oltre la LAN. Con Let’s Encrypt e Certbot il lavoro è rapido. Il punto non è solo avere HTTPS, ma anche evitare che credenziali e token transitino in chiaro nella rete.

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

Dopo l’emissione, verifica il rinnovo automatico. Un certificato che scade perché nessuno ha controllato il timer systemd è un errore banale ma ancora molto comune.

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

Verifiche post-installazione che evitano sorprese

Una volta completata l’installazione, non fermarti alla pagina home. Controlla almeno quattro cose: stato del servizio, connessione al database, uso memoria e spazio disco. Sono le aree che tipicamente si rompono prima in un SonarQube appena installato.

systemctl is-active sonarqube
systemctl status postgresql --no-pager
free -h
df -h / /opt/sonarqube

Se vuoi un controllo più preciso, guarda i log applicativi in `/opt/sonarqube/logs/`. I file utili di solito sono `sonar.log`, `web.log`, `ce.log` e `es.log`. Il pattern conta: errori nel database finiscono spesso in `web.log`, mentre problemi Elasticsearch emergono in `es.log`.

tail -n 50 /opt/sonarqube/logs/sonar.log
tail -n 50 /opt/sonarqube/logs/web.log
tail -n 50 /opt/sonarqube/logs/ce.log
tail -n 50 /opt/sonarqube/logs/es.log

Se il file `es.log` segnala `vm.max_map_count` insufficiente o errori di mmap, il fix è nei parametri kernel, non in SonarQube. Questo è il tipo di dettaglio che conviene riconoscere subito per non perdere ore in tentativi inutili.

Errori tipici e come leggerli senza andare a tentativi

Un errore di database di solito appare come impossibilità di aprire connessioni JDBC o autenticazione fallita. In quel caso la verifica più veloce è provare la connessione con `psql` usando le stesse credenziali configurate nell’applicazione.

psql -h localhost -U sonar -d sonarqube -c 'select 1;'

Se il login fallisce, il problema è nel database, nella password o nelle ACL. Se invece la query passa e SonarQube no, il difetto sta nella configurazione dell’URL JDBC o nella risoluzione DNS del nome host usato nella stringa.

Un’altra classe di problemi riguarda la memoria. Se il processo viene terminato o il servizio resta in stato flapping, guarda `dmesg` e i log di sistema per capire se c’è stato un OOM killer. È importante perché in quel caso cambiare solo parametri dell’app senza aumentare RAM non risolve.

dmesg -T | grep -i -E 'oom|killed process|sonarqube'
journalctl -k -b | grep -i oom

Backup e rollback ragionevoli

Prima di fare cambiamenti importanti, salva almeno `sonar.properties`, l’unit systemd e, se il sistema è già in uso, un backup del database. È il minimo sindacale per avere un rollback credibile. Senza questi elementi, ogni modifica diventa un salto nel buio.

sudo cp /opt/sonarqube/conf/sonar.properties /opt/sonarqube/conf/sonar.properties.pre-change
sudo cp /etc/systemd/system/sonarqube.service /etc/systemd/system/sonarqube.service.pre-change
sudo systemctl daemon-reload

Per il database, usa il dump di PostgreSQL se stai cambiando versione o host. Non fare affidamento solo sulla copia dei file della directory dati: per SonarQube il database è il vero stato applicativo.

pg_dump -h localhost -U sonar sonarqube | gzip > sonarqube-$(date +%F).sql.gz

Conclusione operativa: cosa rende stabile l’installazione

Su Ubuntu 20.04 LTS, SonarQube si installa senza drama solo quando tratti con la stessa attenzione applicazione, JVM, database e sistema operativo. La procedura non è complicata, ma è facile sbagliarla se si salta la parte di verifica. In pratica: Java corretto, PostgreSQL dedicato, limiti kernel applicati, servizio systemd pulito e reverse proxy solo se serve davvero.

Se dopo l’installazione vuoi una macchina che regga nel tempo, il vero lavoro non è “farlo partire”, ma misurare subito memoria, disco, log e tempi di risposta. È lì che si vede se l’istanza è pronta per un uso normale o se va ancora rifinita prima di esporla agli utenti.