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.
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
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
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 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
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
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
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
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
| Symptom | Cause | Fix |
|---|---|---|
| SonarQube nodes can't connect to database | PostgreSQL configuration or firewall | Check pg_hba.conf and firewall rules for port 5432 |
| Search cluster formation fails | Elasticsearch discovery issues | Verify sonar.cluster.search.hosts settings and port 9002 |
| HAProxy shows backend servers as down | Health check failing | Check SonarQube status: curl http://node:9000/api/system/status |
| PostgreSQL replication lag | Network or resource constraints | Monitor with SELECT * FROM pg_stat_replication; |
| SonarQube startup fails with clustering | Node configuration mismatch | Verify unique node names and correct host IPs in sonar.properties |
| SSL certificate errors | Invalid or expired certificates | Regenerate certificates and update HAProxy configuration |
Next steps
- Configure LDAP authentication for centralized user management
- Set up quality gates and project analysis for code quality enforcement
- Monitor HAProxy with Prometheus for load balancer observability
- Implement PostgreSQL backup automation for disaster recovery
- Integrate with Jenkins CI/CD for automated code scanning
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# SonarQube High Availability Cluster Installation Script
# Supports: Ubuntu, Debian, AlmaLinux, Rocky Linux, CentOS, RHEL
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Global variables
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="/tmp/sonarqube-ha-install.log"
# Default configuration
PG_PRIMARY_IP="${1:-203.0.113.10}"
PG_STANDBY_IP="${2:-203.0.113.11}"
SONAR_NODE1_IP="${3:-203.0.113.20}"
SONAR_NODE2_IP="${4:-203.0.113.21}"
HAPROXY_IP="${5:-203.0.113.30}"
PG_VERSION="15"
usage() {
echo "Usage: $0 [pg_primary_ip] [pg_standby_ip] [sonar_node1_ip] [sonar_node2_ip] [haproxy_ip]"
echo "Example: $0 10.0.1.10 10.0.1.11 10.0.1.20 10.0.1.21 10.0.1.30"
exit 1
}
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" | tee -a "$LOG_FILE"
}
warn() {
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}" | tee -a "$LOG_FILE"
}
error() {
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}" | tee -a "$LOG_FILE"
exit 1
}
cleanup() {
warn "Installation failed. Check $LOG_FILE for details."
exit 1
}
trap cleanup ERR
detect_distro() {
if [ ! -f /etc/os-release ]; then
error "Cannot detect Linux distribution"
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
SERVICE_CMD="systemctl"
FIREWALL_CMD="ufw"
PG_CONFIG_DIR="/etc/postgresql/$PG_VERSION/main"
PG_DATA_DIR="/var/lib/postgresql/$PG_VERSION/main"
PG_SERVICE="postgresql"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
SERVICE_CMD="systemctl"
FIREWALL_CMD="firewall-cmd"
PG_CONFIG_DIR="/var/lib/pgsql/$PG_VERSION/data"
PG_DATA_DIR="/var/lib/pgsql/$PG_VERSION/data"
PG_SERVICE="postgresql-$PG_VERSION"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
SERVICE_CMD="systemctl"
FIREWALL_CMD="firewall-cmd"
PG_CONFIG_DIR="/var/lib/pgsql/$PG_VERSION/data"
PG_DATA_DIR="/var/lib/pgsql/$PG_VERSION/data"
PG_SERVICE="postgresql-$PG_VERSION"
;;
fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
SERVICE_CMD="systemctl"
FIREWALL_CMD="firewall-cmd"
PG_CONFIG_DIR="/var/lib/pgsql/data"
PG_DATA_DIR="/var/lib/pgsql/data"
PG_SERVICE="postgresql"
;;
*)
error "Unsupported distribution: $ID"
;;
esac
}
check_prerequisites() {
log "[1/10] Checking prerequisites..."
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root or with sudo"
fi
# Validate IP addresses
for ip in "$PG_PRIMARY_IP" "$PG_STANDBY_IP" "$SONAR_NODE1_IP" "$SONAR_NODE2_IP" "$HAPROXY_IP"; do
if ! [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
error "Invalid IP address: $ip"
fi
done
# Check minimum RAM (4GB)
total_ram=$(grep MemTotal /proc/meminfo | awk '{print $2}')
if [ "$total_ram" -lt 4194304 ]; then
warn "System has less than 4GB RAM. Performance may be affected."
fi
}
update_system() {
log "[2/10] Updating system packages..."
$PKG_UPDATE >> "$LOG_FILE" 2>&1
case "$PKG_MGR" in
apt)
$PKG_INSTALL wget curl gnupg2 software-properties-common ntp >> "$LOG_FILE" 2>&1
;;
dnf|yum)
$PKG_INSTALL wget curl gnupg2 chrony >> "$LOG_FILE" 2>&1
;;
esac
}
install_postgresql() {
log "[3/10] Installing PostgreSQL $PG_VERSION..."
case "$PKG_MGR" in
apt)
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - >> "$LOG_FILE" 2>&1
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
apt update >> "$LOG_FILE" 2>&1
$PKG_INSTALL postgresql-$PG_VERSION postgresql-contrib-$PG_VERSION >> "$LOG_FILE" 2>&1
;;
dnf)
$PKG_INSTALL "https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm" >> "$LOG_FILE" 2>&1
$PKG_INSTALL postgresql$PG_VERSION-server postgresql$PG_VERSION-contrib >> "$LOG_FILE" 2>&1
/usr/pgsql-$PG_VERSION/bin/postgresql-$PG_VERSION-setup initdb >> "$LOG_FILE" 2>&1
;;
yum)
$PKG_INSTALL "https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm" >> "$LOG_FILE" 2>&1
$PKG_INSTALL postgresql$PG_VERSION-server postgresql$PG_VERSION-contrib >> "$LOG_FILE" 2>&1
/usr/pgsql-$PG_VERSION/bin/postgresql-$PG_VERSION-setup initdb >> "$LOG_FILE" 2>&1
;;
esac
}
configure_postgresql_primary() {
log "[4/10] Configuring PostgreSQL primary server..."
# Configure postgresql.conf
cat >> "$PG_CONFIG_DIR/postgresql.conf" << EOF
listen_addresses = '*'
wal_level = replica
max_wal_senders = 3
max_replication_slots = 3
archive_mode = on
archive_command = 'test ! -f $PG_DATA_DIR/archive/%f && cp %p $PG_DATA_DIR/archive/%f'
log_replication_commands = on
EOF
# Configure pg_hba.conf
cat >> "$PG_CONFIG_DIR/pg_hba.conf" << EOF
host replication replica $PG_STANDBY_IP/32 md5
host sonarqube sonarqube $SONAR_NODE1_IP/32 md5
host sonarqube sonarqube $SONAR_NODE2_IP/32 md5
EOF
# Create archive directory
mkdir -p "$PG_DATA_DIR/archive"
chown postgres:postgres "$PG_DATA_DIR/archive"
chmod 750 "$PG_DATA_DIR/archive"
$SERVICE_CMD enable $PG_SERVICE
$SERVICE_CMD restart $PG_SERVICE
}
create_database_users() {
log "[5/10] Creating SonarQube database and users..."
sudo -u postgres psql << EOF
CREATE USER replica WITH REPLICATION ENCRYPTED PASSWORD 'replica_secure_pass123';
CREATE USER sonarqube WITH ENCRYPTED PASSWORD 'sonar_secure_pass123';
CREATE DATABASE sonarqube OWNER sonarqube;
GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonarqube;
ALTER DATABASE sonarqube OWNER TO sonarqube;
EOF
}
install_java() {
log "[6/10] Installing Java 11..."
case "$PKG_MGR" in
apt)
$PKG_INSTALL openjdk-11-jdk >> "$LOG_FILE" 2>&1
;;
dnf|yum)
$PKG_INSTALL java-11-openjdk java-11-openjdk-devel >> "$LOG_FILE" 2>&1
;;
esac
}
install_sonarqube() {
log "[7/10] Installing SonarQube..."
SONAR_VERSION="9.9.3.79811"
wget -q "https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-$SONAR_VERSION.zip" -O /tmp/sonarqube.zip
$PKG_INSTALL unzip >> "$LOG_FILE" 2>&1
unzip -q /tmp/sonarqube.zip -d /opt/
mv "/opt/sonarqube-$SONAR_VERSION" /opt/sonarqube
# Create sonarqube user
useradd -r -d /opt/sonarqube -s /bin/bash sonarqube
chown -R sonarqube:sonarqube /opt/sonarqube
chmod 755 /opt/sonarqube
}
configure_sonarqube() {
log "[8/10] Configuring SonarQube..."
cat > /opt/sonarqube/conf/sonar.properties << EOF
sonar.jdbc.username=sonarqube
sonar.jdbc.password=sonar_secure_pass123
sonar.jdbc.url=jdbc:postgresql://$PG_PRIMARY_IP:5432/sonarqube
sonar.cluster.enabled=true
sonar.cluster.node.type=application
sonar.cluster.hosts=$SONAR_NODE1_IP:9003,$SONAR_NODE2_IP:9003
sonar.cluster.search.hosts=$SONAR_NODE1_IP:9001,$SONAR_NODE2_IP:9001
sonar.auth.jwtBase64Hs256Secret=$(openssl rand -base64 64)
EOF
chown sonarqube:sonarqube /opt/sonarqube/conf/sonar.properties
chmod 640 /opt/sonarqube/conf/sonar.properties
# Create systemd service
cat > /etc/systemd/system/sonarqube.service << EOF
[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
User=sonarqube
Group=sonarqube
Restart=always
LimitNOFILE=131072
LimitNPROC=8192
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable sonarqube
}
install_haproxy() {
log "[9/10] Installing and configuring HAProxy..."
$PKG_INSTALL haproxy >> "$LOG_FILE" 2>&1
cat > /etc/haproxy/haproxy.cfg << EOF
global
log stdout local0
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend sonarqube_frontend
bind *:80
default_backend sonarqube_servers
backend sonarqube_servers
balance roundrobin
option httpchk GET /api/system/status
server sonar1 $SONAR_NODE1_IP:9000 check
server sonar2 $SONAR_NODE2_IP:9000 check
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 30s
stats admin if TRUE
EOF
systemctl enable haproxy
systemctl restart haproxy
}
configure_firewall() {
log "[10/10] Configuring firewall..."
case "$FIREWALL_CMD" in
ufw)
ufw --force enable >> "$LOG_FILE" 2>&1
ufw allow 5432/tcp >> "$LOG_FILE" 2>&1 # PostgreSQL
ufw allow 9000/tcp >> "$LOG_FILE" 2>&1 # SonarQube
ufw allow 9001/tcp >> "$LOG_FILE" 2>&1 # Elasticsearch
ufw allow 9003/tcp >> "$LOG_FILE" 2>&1 # Cluster communication
ufw allow 80/tcp >> "$LOG_FILE" 2>&1 # HAProxy
ufw allow 8404/tcp >> "$LOG_FILE" 2>&1 # HAProxy stats
;;
firewall-cmd)
systemctl enable firewalld
systemctl start firewalld >> "$LOG_FILE" 2>&1
firewall-cmd --permanent --add-port=5432/tcp >> "$LOG_FILE" 2>&1
firewall-cmd --permanent --add-port=9000/tcp >> "$LOG_FILE" 2>&1
firewall-cmd --permanent --add-port=9001/tcp >> "$LOG_FILE" 2>&1
firewall-cmd --permanent --add-port=9003/tcp >> "$LOG_FILE" 2>&1
firewall-cmd --permanent --add-port=80/tcp >> "$LOG_FILE" 2>&1
firewall-cmd --permanent --add-port=8404/tcp >> "$LOG_FILE" 2>&1
firewall-cmd --reload
Review the script before running. Execute with: bash install.sh