1 15/04/2026 11 min

SonarQube su Ubuntu 22.04: scelta architetturale prima dell’installazione

Su Ubuntu 22.04 LTS la strada pulita per SonarQube è separare bene i pezzi: Java dedicato, PostgreSQL locale o remoto, servizio systemd e un reverse proxy davanti se devi esporlo in rete. Installarlo “al volo” e basta funziona solo in laboratorio; in produzione ti servono invece prerequisiti chiari, limiti di risorse e una procedura di rollback minima. SonarQube non è un servizio leggero: se lo tratti come una web app qualunque, prima o poi ti presenta il conto in JVM, database e storage.

La versione di Ubuntu non è un dettaglio cosmetico. 22.04 porta una base solida, systemd maturo e un ecosistema Java coerente. La parte delicata è la compatibilità tra SonarQube e la JVM: oggi conviene usare Java 17 per le release moderne di SonarQube. Se sbagli versione, il sintomo tipico non è elegante: il servizio parte e poi muore, oppure non parte proprio, lasciando messaggi di errore nei log. Qui l’obiettivo è evitare tentativi ciechi e arrivare subito a un’installazione ripetibile.

Prerequisiti reali: utente, kernel, database e limiti di sistema

Prima di copiare file o lanciare installer, verifica questi punti. Sono quelli che più spesso fanno perdere tempo quando SonarQube sembra “rotto” ma in realtà sta solo sbattendo contro un prerequisito mancante.

  • Ubuntu 22.04 aggiornato e con accesso sudo.
  • Almeno 2 vCPU e 4 GB di RAM per test piccoli; per uso serio meglio salire. Con meno, Elasticsearch e la JVM si pestano i piedi.
  • PostgreSQL 13 o superiore, preferibilmente locale o su rete affidabile.
  • Java 17 installato solo per SonarQube, non “a caso” come default dell’host se hai altri stack che dipendono da versioni diverse.
  • Permessi per modificare `sysctl` e `limits.d` se il server è nuovo o molto ristretto.

Il punto più sottovalutato è il kernel tuning. SonarQube usa Elasticsearch embedded, quindi dipende da parametri di sistema come i file descriptor e le virtual memory map. Se li ignori, poi ti ritrovi errori del tipo “max virtual memory areas vm.max_map_count [too low]” o un avvio che si interrompe senza una causa immediata per chi non sa dove guardare.

Installazione della base: Java 17, PostgreSQL e utente dedicato

Parti dalla base. Non usare root per l’esecuzione del servizio. Crea un utente dedicato e tieni separati dati, log e binari. Questo riduce il blast radius se qualcosa va storto e rende più semplice il rollback.

1. Aggiorna il sistema e installa i pacchetti necessari:

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

2. Installa Java 17:

sudo apt -y install openjdk-17-jdk
java -version

L’output atteso deve mostrare una versione 17.x. Se vedi una release diversa, fermati e correggi prima di andare oltre. Con SonarQube la JVM non è un optional intercambiabile.

3. Installa PostgreSQL:

sudo apt -y install postgresql postgresql-contrib
sudo systemctl enable --now postgresql
sudo systemctl status postgresql --no-pager

4. Crea database e utente applicativo. Usa una password robusta e non salvarla in chiaro dentro documenti operativi o ticket.

sudo -u postgres psql
CREATE USER sonarqube WITH ENCRYPTED PASSWORD 'PASSWORD_FORTE';
CREATE DATABASE sonarqube OWNER sonarqube TEMPLATE template0 ENCODING 'UTF8';
\q

Se devi automatizzare, sostituisci la password in chiaro con un secret manager o con un meccanismo di provisioning sicuro. La regola pratica è semplice: nei documenti operativi pubblici non lasciare segreti riutilizzabili.

Parametri di sistema: il punto che evita il 90% degli avvii falliti

SonarQube con Elasticsearch embedded richiede almeno alcuni aggiustamenti lato kernel e limiti utente. Il controllo va fatto prima di avviare il servizio, non dopo aver perso mezz’ora sui log applicativi.

1. Imposta `vm.max_map_count`:

echo 'vm.max_map_count=262144' | sudo tee /etc/sysctl.d/99-sonarqube.conf
sudo sysctl --system
sysctl vm.max_map_count

Il valore atteso è `vm.max_map_count = 262144`. Se resta più basso, SonarQube può fallire durante il bootstrap di Elasticsearch.

2. Aumenta i file descriptor e i processi per l’utente che eseguirà SonarQube. La configurazione classica passa da `limits.d`:

sudo useradd --system --create-home --shell /bin/bash sonarqube
sudo tee /etc/security/limits.d/99-sonarqube.conf > /dev/null <<'EOF'
sonarqube   -   nofile   131072
sonarqube   -   nproc    8192
EOF

Con systemd i limiti vanno poi ribaditi nel service file, perché i limiti PAM da soli non bastano sempre per i servizi avviati dal boot.

Download, directory e permessi: struttura pulita e reversibile

La regola operativa è semplice: binari in una directory versionata, dati e log separati, ownership coerente. Se devi aggiornare o fare rollback, devi poter cambiare directory senza riscrivere mezzo sistema.

1. Scarica la release di SonarQube che ti serve. Qui uso un esempio generico: sostituisci l’URL con la versione effettiva che vuoi installare, verificando la compatibilità con Java 17 e con eventuali plugin di terze parti.

cd /tmp
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-NEW_VERSION.zip
sudo unzip sonarqube-NEW_VERSION.zip -d /opt
sudo mv /opt/sonarqube-NEW_VERSION /opt/sonarqube

2. Assegna i permessi all’utente dedicato:

sudo chown -R sonarqube:sonarqube /opt/sonarqube

3. Crea directory esterne per dati e log se vuoi tenere meglio separati binari e runtime. In ambienti con cicli di upgrade frequenti è una scelta che paga.

sudo mkdir -p /var/sonarqube/data /var/sonarqube/temp /var/sonarqube/logs
sudo chown -R sonarqube:sonarqube /var/sonarqube

Configurazione di SonarQube: database, porte e memoria JVM

Il file centrale è `conf/sonar.properties`. Qui definisci il database e, se serve, il binding della web app. Non complicarlo con opzioni inutili finché non hai un’installazione stabile.

Apri il file e imposta almeno questi parametri:

sudo nano /opt/sonarqube/conf/sonar.properties
sonar.jdbc.username=sonarqube
sonar.jdbc.password=PASSWORD_FORTE
sonar.jdbc.url=jdbc:postgresql://127.0.0.1/sonarqube
sonar.web.host=0.0.0.0
sonar.web.port=9000

Se il database è remoto, sostituisci `127.0.0.1` con l’IP o il DNS del server PostgreSQL, ma aggiungi prima una verifica di rete: se apri firewall e poi scopri che il database non risponde, hai solo aumentato la superficie d’attacco senza guadagno operativo.

La JVM va dimensionata con criterio. Su server piccoli puoi partire con valori moderati, ma non lasciare tutto al default se hai risorse note. Modifica `conf/sonar.properties` o il file di avvio JVM secondo la release che stai usando. L’obiettivo non è “più memoria possibile”, ma evitare swap e pause lunghe.

sudo nano /opt/sonarqube/conf/sonar.properties

Se la tua versione usa `sonar.web.javaOpts` e `sonar.search.javaOpts`, un’impostazione iniziale prudente può essere questa, da adattare al RAM reale:

sonar.web.javaOpts=-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError
sonar.search.javaOpts=-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError

Su installazioni più grandi questi valori vanno rivisti. La metrica da guardare non è solo il consumo medio, ma la stabilità: swap, OOM killer, tempi di avvio e latenza dell’interfaccia.

Servizio systemd: avvio controllato e rollback semplice

Creare un’unità systemd ti dà un vantaggio pratico: startup coerente, restart automatico e log centralizzati in journal. È anche il punto giusto per mettere i limiti che il processo deve rispettare.

1. Crea il file `/etc/systemd/system/sonarqube.service`:

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=sonarqube
Group=sonarqube
Restart=always
LimitNOFILE=131072
LimitNPROC=8192
TimeoutStartSec=300

[Install]
WantedBy=multi-user.target
EOF

2. Ricarica systemd e abilita il servizio:

sudo systemctl daemon-reload
sudo systemctl enable --now sonarqube
sudo systemctl status sonarqube --no-pager

Se il servizio fallisce, il primo posto da guardare è `journalctl -u sonarqube -b --no-pager`. Non partire subito a modificare file a caso: prima identifica il layer che sta fallendo, poi fai una correzione minima e reversibile.

Verifica operativa: cosa deve rispondere prima di considerare l’installazione chiusa

Una volta avviato il servizio, verifica che la porta 9000 sia in ascolto e che la web UI risponda. Non serve ancora il reverse proxy per confermare che il core funzioni.

ss -ltnp | grep 9000
curl -I http://127.0.0.1:9000

Il primo comando deve mostrare un listener su `:9000`. Il secondo deve restituire una risposta HTTP, spesso un redirect o un codice 200/302 a seconda dello stato iniziale. Se ottieni timeout o connection refused, il problema è ancora nel servizio o nei prerequisiti, non nel browser.

Accedi quindi alla UI e completa il primo login. In molte versioni l’account iniziale è `admin` / `admin`, con richiesta di cambio password al primo accesso. Appena entri, cambia subito la password e crea un utente amministrativo nominativo. L’account di default non deve restare utilizzabile oltre il bootstrap iniziale.

Reverse proxy e TLS: quando esporre SonarQube in modo corretto

Esporre direttamente la porta 9000 su Internet non è una buona idea. In un contesto serio metti davanti un reverse proxy come Nginx o Apache, termina il TLS lì e lascia SonarQube su loopback o su rete privata. Questo riduce la superficie d’attacco e ti consente di gestire certificati, header e limiti di accesso in modo più pulito.

Con Nginx, il concetto base è questo: proxy verso `127.0.0.1:9000`, header corretti per WebSocket e path coerente. L’installazione del certificato può avvenire con Let’s Encrypt o con PKI interna, ma il punto importante è che il certificato non va mai messo in chiaro in documenti operativi.

Un esempio minimo di blocco server può essere strutturato così, tenendo conto che la configurazione completa dipende dal tuo dominio e dalla tua policy TLS:

server {
    listen 443 ssl http2;
    server_name sonar.example.com;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-Host $host;
    }
}

Se usi proxy esterni, CDN o WAF, verifica che non alterino in modo aggressivo gli header o i timeout. SonarQube è abbastanza sensibile ai proxy mal allineati: la UI può aprirsi, ma alcune funzioni restano instabili o lente.

Tuning minimo per non trasformare il server in un collo di bottiglia

Il tuning non va fatto a sentimento. La metrica da osservare è la combinazione di latenza UI, tempo di analisi, error rate e pressione memoria. Se la dashboard si apre ma le analisi si trascinano, non stai guardando il problema giusto.

  • Controlla `free -h` e `top` per capire se la JVM sta entrando in swap.
  • Guarda `journalctl -u sonarqube -b` per errori di startup o crash loop.
  • Monitora il database con `pg_stat_activity` se le query diventano lente.
  • Se il disco è quasi pieno, aspettati sintomi strani: Elasticsearch e PostgreSQL non gradiscono filesystem al limite.

Un server con poco spazio o RAM può sembrare funzionante per giorni e poi degradare di colpo quando aumentano le analisi o arrivano picchi di accesso. Per questo conviene sempre fissare un baseline: tempo di login, tempo di apertura dashboard, durata media di una scansione e uso RAM a riposo.

Errori tipici e come leggerli senza perdere tempo

Ci sono alcuni errori ricorrenti che vale la pena riconoscere al volo. Se li intercetti subito, eviti di toccare componenti sani.

  1. Java sbagliato: il servizio non parte o esce subito. Verifica con `java -version` e con i log di startup.
  2. PostgreSQL non raggiungibile: errori di connessione nel log applicativo. Verifica `systemctl status postgresql` e il campo `sonar.jdbc.url`.
  3. vm.max_map_count basso: Elasticsearch fallisce in bootstrap. Verifica con `sysctl vm.max_map_count`.
  4. Permessi errati: SonarQube non legge o non scrive in directory di dati/log. Verifica ownership e path reali.
  5. Memoria insufficiente: il processo rallenta o viene ucciso. Verifica `dmesg -T | grep -i oom` e i limiti JVM.

Quando qualcosa non torna, la sequenza giusta è: layer, evidenza, mitigazione, fix strutturale. Prima capisci se sei bloccato su DNS, rete, database, JVM o storage; poi applichi la correzione minima. È il modo più rapido per non peggiorare un sistema già fragile.

Manutenzione dopo l’installazione: backup, upgrade e igiene operativa

Una volta online, SonarQube va trattato come un servizio applicativo con stato. Non basta “funziona adesso”. Servono backup del database, backup della configurazione e una procedura di upgrade provata su ambiente non produttivo.

Il backup minimo include:

  • dump PostgreSQL del database `sonarqube`;
  • `/opt/sonarqube/conf/`;
  • eventuali certificati e configurazioni del reverse proxy;
  • eventuali plugin aggiunti manualmente.

Prima di aggiornare, fermati e confronta release notes, compatibilità plugin e requisiti Java. Il rollback più semplice è avere la directory precedente pronta, il database salvato e il servizio puntato di nuovo alla versione nota come buona. Se invece aggiorni “sopra” senza piano, trasformi un cambio ordinario in un incidente.

In sintesi operativa: su Ubuntu 22.04 SonarQube si installa bene se rispetti tre vincoli non negoziabili — Java corretto, PostgreSQL sano, tuning kernel/limiti adeguati. Tutto il resto viene dopo. Se parti da lì, l’installazione resta leggibile, supportabile e soprattutto reversibile.