Configure SonarQube high availability clustering with PostgreSQL and load balancing

Advanced 90 min Apr 15, 2026 25 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up enterprise-grade SonarQube clustering with PostgreSQL database replication, multiple application nodes, and HAProxy load balancing for zero-downtime code quality analysis across distributed teams.

Prerequisites

  • 5 servers with 4GB RAM each
  • Network connectivity between all nodes
  • Basic understanding of PostgreSQL replication
  • Domain name or load balancer IP for access
  • SSL certificates for HTTPS

What this solves

SonarQube high availability clustering eliminates single points of failure in your code quality analysis infrastructure. This setup provides automatic failover, horizontal scaling, and zero-downtime deployments for enterprise environments where continuous code analysis is critical.

Prerequisites

You need at least 5 servers with minimum 4GB RAM each: 1 PostgreSQL primary, 1 PostgreSQL standby, 2 SonarQube application nodes, and 1 HAProxy load balancer. All servers should have network connectivity and synchronized time using NTP.

Note: This tutorial assumes you have basic knowledge of PostgreSQL replication and load balancing concepts. For simpler setups, consider single-node SonarQube installation first.

Step-by-step configuration

Update all systems

Start by updating package repositories on all five servers to ensure consistent package versions.

sudo apt update && sudo apt upgrade -y
sudo apt install -y wget curl gnupg2 software-properties-common
sudo dnf update -y
sudo dnf install -y wget curl gnupg2

Configure PostgreSQL primary server

Install PostgreSQL 15 on your primary database server (203.0.113.10) and configure it for streaming replication.

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
sudo apt install -y postgresql-15 postgresql-contrib-15
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
sudo dnf install -y postgresql15-server postgresql15-contrib
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb

Configure PostgreSQL for clustering

Modify PostgreSQL configuration to enable replication and create the SonarQube database with proper permissions.

listen_addresses = '*'
wal_level = replica
max_wal_senders = 3
max_replication_slots = 3
archive_mode = on
archive_command = 'test ! -f /var/lib/postgresql/15/main/archive/%f && cp %p /var/lib/postgresql/15/main/archive/%f'
log_replication_commands = on
# Add these lines after existing entries
host replication replica 203.0.113.11/32 md5
host sonarqube sonarqube 203.0.113.20/32 md5
host sonarqube sonarqube 203.0.113.21/32 md5
sudo mkdir -p /var/lib/postgresql/15/main/archive
sudo chown postgres:postgres /var/lib/postgresql/15/main/archive
sudo systemctl restart postgresql

Create SonarQube database and replication user

Set up the database schema and users required for SonarQube clustering and PostgreSQL replication.

sudo -u postgres psql -c "CREATE USER replica WITH REPLICATION ENCRYPTED PASSWORD 'replica_secure_pass123';"
sudo -u postgres psql -c "CREATE DATABASE sonarqube OWNER sonarqube;"
sudo -u postgres psql -c "CREATE USER sonarqube WITH ENCRYPTED PASSWORD 'sonar_secure_pass123';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonarqube;"
sudo -u postgres psql -c "ALTER DATABASE sonarqube OWNER TO sonarqube;"

Set up PostgreSQL standby server

Configure the standby PostgreSQL server (203.0.113.11) for streaming replication from the primary.

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
sudo apt install -y postgresql-15
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
sudo dnf install -y postgresql15-server
sudo systemctl stop postgresql
sudo -u postgres rm -rf /var/lib/postgresql/15/main/*
sudo -u postgres pg_basebackup -h 203.0.113.10 -D /var/lib/postgresql/15/main -U replica -v -P -W -R

Configure PostgreSQL standby

Set up the standby server configuration and start replication.

primary_conninfo = 'host=203.0.113.10 port=5432 user=replica password=replica_secure_pass123'
restore_command = 'cp /var/lib/postgresql/15/main/archive/%f %p'
recovery_target_timeline = 'latest'
sudo touch /var/lib/postgresql/15/main/standby.signal
sudo chown postgres:postgres /var/lib/postgresql/15/main/standby.signal
sudo systemctl start postgresql
sudo systemctl enable postgresql

Install Java on SonarQube nodes

Install OpenJDK 17 on both SonarQube application servers (203.0.113.20 and 203.0.113.21).

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

Download and install SonarQube

Download SonarQube Community or Developer Edition and install it on both application servers.

cd /opt
sudo wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-10.3.0.82913.zip
sudo unzip sonarqube-10.3.0.82913.zip
sudo mv sonarqube-10.3.0.82913 sonarqube
sudo useradd -r -s /bin/false sonarqube
sudo chown -R sonarqube:sonarqube /opt/sonarqube
sudo chmod +x /opt/sonarqube/bin/linux-x86-64/sonar.sh

Configure SonarQube clustering

Configure both SonarQube nodes for clustering with shared database and unique node identifiers.

# Database configuration
sonar.jdbc.username=sonarqube
sonar.jdbc.password=sonar_secure_pass123
sonar.jdbc.url=jdbc:postgresql://203.0.113.10:5432/sonarqube

Clustering configuration

sonar.cluster.enabled=true sonar.cluster.node.type=application sonar.cluster.node.name=sonarqube-app-1 sonar.cluster.node.host=203.0.113.20 sonar.cluster.node.port=9003

Elasticsearch configuration

sonar.cluster.search.hosts=203.0.113.20:9002,203.0.113.21:9002

Web server configuration

sonar.web.host=203.0.113.20 sonar.web.port=9000

JVM options

sonar.web.javaOpts=-server -Xms2g -Xmx2g -XX:+HeapDumpOnOutOfMemoryError sonar.ce.javaOpts=-server -Xms2g -Xmx2g -XX:+HeapDumpOnOutOfMemoryError
Important: Change sonar.cluster.node.name to "sonarqube-app-2" and sonar.cluster.node.host to "203.0.113.21" on the second node.

Configure Elasticsearch for clustering

Set up Elasticsearch configuration for SonarQube search clustering on both nodes.

# Add these Elasticsearch settings to existing configuration
sonar.search.host=0.0.0.0
sonar.search.port=9002
sonar.search.javaOpts=-Xms2g -Xmx2g

Cluster discovery settings

sonar.search.initialStateTimeout=300s

Create SonarQube systemd service

Set up systemd service files for automatic startup and management on both application servers.

[Unit]
Description=SonarQube service
After=syslog.target network.target

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

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

Install and configure HAProxy

Set up HAProxy on the load balancer server (203.0.113.30) for distributing traffic between SonarQube nodes.

sudo apt install -y haproxy
sudo dnf install -y haproxy

Configure HAProxy load balancing

Set up HAProxy configuration with health checks and session stickiness for SonarQube clustering.

global
    daemon
    maxconn 4096
    log stdout local0 info
    tune.ssl.default-dh-param 2048

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
    option httplog
    option dontlognull
    option redispatch
    retries 3
    maxconn 3000

frontend sonarqube_frontend
    bind *:80
    bind *:443 ssl crt /etc/ssl/certs/sonarqube.pem
    redirect scheme https if !{ ssl_fc }
    default_backend sonarqube_backend

backend sonarqube_backend
    balance roundrobin
    option httpchk GET /api/system/status
    http-check expect status 200
    cookie SONARQUBE_SERVER insert indirect nocache
    server sonar1 203.0.113.20:9000 check cookie sonar1 maxconn 1000
    server sonar2 203.0.113.21:9000 check cookie sonar2 maxconn 1000

listen haproxy_stats
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 30s
    stats admin if TRUE

Configure SSL certificates

Set up SSL certificates for secure HTTPS access to the SonarQube cluster.

sudo mkdir -p /etc/ssl/certs
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /tmp/sonarqube.key -out /tmp/sonarqube.crt \
    -subj "/C=US/ST=State/L=City/O=Organization/CN=sonarqube.example.com"
sudo cat /tmp/sonarqube.crt /tmp/sonarqube.key > /etc/ssl/certs/sonarqube.pem
sudo chmod 600 /etc/ssl/certs/sonarqube.pem
sudo rm /tmp/sonarqube.key /tmp/sonarqube.crt

Start HAProxy and enable services

Enable and start HAProxy with the new configuration for load balancing.

sudo systemctl enable haproxy
sudo systemctl start haproxy
sudo systemctl status haproxy

Configure firewall rules

Open necessary ports for SonarQube clustering, PostgreSQL replication, and HAProxy load balancing.

# On SonarQube nodes
sudo ufw allow 9000/tcp
sudo ufw allow 9002/tcp
sudo ufw allow 9003/tcp

On PostgreSQL servers

sudo ufw allow 5432/tcp

On HAProxy server

sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 8404/tcp
# On SonarQube nodes
sudo firewall-cmd --permanent --add-port=9000/tcp
sudo firewall-cmd --permanent --add-port=9002/tcp
sudo firewall-cmd --permanent --add-port=9003/tcp

On PostgreSQL servers

sudo firewall-cmd --permanent --add-port=5432/tcp

On HAProxy server

sudo firewall-cmd --permanent --add-port=80/tcp sudo firewall-cmd --permanent --add-port=443/tcp sudo firewall-cmd --permanent --add-port=8404/tcp sudo firewall-cmd --reload

Verify your setup

Test the high availability cluster by checking each component and performing failover tests.

# Check PostgreSQL replication status
sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"

Verify SonarQube cluster status

curl -u admin:admin http://203.0.113.20:9000/api/system/status curl -u admin:admin http://203.0.113.21:9000/api/system/status

Test HAProxy load balancing

curl -I http://203.0.113.30 curl -I https://203.0.113.30

Check HAProxy stats

curl http://203.0.113.30:8404/stats

Verify all services are running

sudo systemctl status postgresql sonarqube haproxy

Configure automatic failover

Set up monitoring and automatic failover for PostgreSQL using tools like Patroni or manual scripting. For basic monitoring, you can integrate with existing monitoring solutions like Prometheus and Grafana.

#!/bin/bash
PRIMARY_HOST="203.0.113.10"
STANDBY_HOST="203.0.113.11"
HEALTH_CHECK="SELECT 1;"

if ! sudo -u postgres psql -h $PRIMARY_HOST -c "$HEALTH_CHECK" >/dev/null 2>&1; then
    echo "Primary PostgreSQL failed, promoting standby"
    sudo -u postgres pg_ctl promote -D /var/lib/postgresql/15/main
    # Update SonarQube configuration to use new primary
    sed -i "s/$PRIMARY_HOST/$STANDBY_HOST/g" /opt/sonarqube/conf/sonar.properties
    sudo systemctl restart sonarqube
fi
sudo chmod +x /usr/local/bin/check-postgres.sh
echo "/2    * /usr/local/bin/check-postgres.sh" | sudo crontab -

Performance optimization

Optimize the cluster for production workloads by tuning PostgreSQL, SonarQube, and HAProxy settings.

# Add these performance optimizations
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 4MB
maintenance_work_mem = 64MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
# Performance tuning for SonarQube
sonar.web.javaOpts=-server -Xms4g -Xmx4g -XX:+HeapDumpOnOutOfMemoryError -XX:NewRatio=1 -XX:+UseG1GC
sonar.ce.javaOpts=-server -Xms4g -Xmx4g -XX:+HeapDumpOnOutOfMemoryError -XX:NewRatio=1 -XX:+UseG1GC
sonar.search.javaOpts=-Xms4g -Xmx4g -XX:+UseG1GC

Common issues

SymptomCauseFix
SonarQube nodes can't connect to databasePostgreSQL configuration or firewallCheck pg_hba.conf and firewall rules for port 5432
Search cluster formation failsElasticsearch discovery issuesVerify sonar.cluster.search.hosts settings and port 9002
HAProxy shows backend servers as downHealth check failingCheck SonarQube status: curl http://node:9000/api/system/status
PostgreSQL replication lagNetwork or resource constraintsMonitor with SELECT * FROM pg_stat_replication;
SonarQube startup fails with clusteringNode configuration mismatchVerify unique node names and correct host IPs in sonar.properties
SSL certificate errorsInvalid or expired certificatesRegenerate certificates and update HAProxy configuration

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.