Configuring Nexus Repository High Availability With PostgreSQL Clustering
Configuring Nexus Repository High Availability with PostgreSQL Clustering
Setting up high availability (HA) for Nexus Repository isn't just about avoiding downtime—it's about building a bulletproof artifact management system that your entire engineering organization can rely on. I've seen too many teams learn this lesson the hard way when their single Nexus instance goes down during a critical deployment window.
Today, we're going to build a production-ready Nexus Repository HA setup with PostgreSQL clustering. By the end of this guide, you'll have a system that can handle node failures without breaking a sweat.
Why High Availability Matters for Nexus Repository
Before we dive into the technical details, let's talk about why this matters. Nexus Repository sits at the heart of your software delivery pipeline. When it's down:
- Developers can't push or pull artifacts
- CI/CD pipelines fail
- Docker builds stop working
- Maven/npm/PyPI dependencies become unreachable
I've been in war rooms where a single Nexus failure cascaded into hours of downtime across dozens of applications. Trust me, you don't want to be there.
Architecture Overview
Our HA setup consists of:
- Multiple Nexus Repository Pro instances (minimum 3 for true HA)
- PostgreSQL cluster with streaming replication
- Load balancer (HAProxy or similar)
- Shared blob storage (NFS, AWS EFS, or similar)
Here's the key insight most people miss: Nexus Repository Pro uses a shared-nothing architecture for compute but requires shared storage for blobs and a clustered database for metadata.
Prerequisites and Planning
You'll need:
- Nexus Repository Pro license (HA is not available in OSS)
- At least 3 servers for Nexus nodes
- 3 servers for PostgreSQL cluster
- Shared storage solution
- Load balancer
Resource Planning:
- Each Nexus node: 8GB RAM minimum, 16GB recommended
- PostgreSQL nodes: 4GB RAM minimum per node
- Network: Low-latency connections between all components
Setting Up PostgreSQL Cluster
Let's start with the foundation—our PostgreSQL cluster. We'll use PostgreSQL 13 with streaming replication and automatic failover via Patroni.
Installing PostgreSQL and Patroni
On all PostgreSQL nodes:
# Install PostgreSQL 13
sudo apt update
sudo apt install -y postgresql-13 postgresql-client-13 postgresql-contrib-13
# Install Patroni and dependencies
sudo apt install -y python3-pip python3-dev
pip3 install patroni psycopg2-binary
# Install etcd for distributed configuration
sudo apt install -y etcd
Configuring etcd Cluster
First, let's set up etcd for cluster coordination. On each etcd node (can be same as PostgreSQL nodes):
# /etc/etcd/etcd.conf.yml
name: 'etcd-node-1' # Change for each node
data-dir: /var/lib/etcd
listen-client-urls: http://0.0.0.0:2379
advertise-client-urls: http://10.0.1.10:2379 # This node's IP
listen-peer-urls: http://0.0.0.0:2380
initial-advertise-peer-urls: http://10.0.1.10:2380
initial-cluster: 'etcd-node-1=http://10.0.1.10:2380,etcd-node-2=http://10.0.1.11:2380,etcd-node-3=http://10.0.1.12:2380'
initial-cluster-state: 'new'
initial-cluster-token: 'nexus-cluster'
Start etcd on all nodes:
sudo systemctl enable etcd
sudo systemctl start etcd
Configuring Patroni
Create the Patroni configuration on each PostgreSQL node:
# /etc/patroni/patroni.yml
scope: nexus-cluster
namespace: /db/
name: postgres-node-1 # Change for each node
restapi:
listen: 0.0.0.0:8008
connect_address: 10.0.1.20:8008 # This node's IP
etcd:
hosts: 10.0.1.10:2379,10.0.1.11:2379,10.0.1.12:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 30
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
max_connections: 200
shared_preload_libraries: pg_stat_statements
wal_level: replica
hot_standby: on
max_wal_senders: 10
max_replication_slots: 10
wal_keep_segments: 8
archive_mode: on
archive_timeout: 1800s
archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
initdb:
- encoding: UTF8
- data-checksums
postgresql:
listen: 0.0.0.0:5432
connect_address: 10.0.1.20:5432 # This node's IP
data_dir: /var/lib/postgresql/13/main
bin_dir: /usr/lib/postgresql/13/bin
pgpass: /tmp/pgpass
authentication:
replication:
username: replicator
password: your-replication-password
superuser:
username: postgres
password: your-postgres-password
parameters:
unix_socket_directories: '/var/run/postgresql'
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
Starting PostgreSQL Cluster
Create a systemd service for Patroni:
# /etc/systemd/system/patroni.service
[Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target
[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
KillMode=process
TimeoutSec=30
Restart=no
[Install]
WantedBy=multi-user.target
Start Patroni on all nodes:
sudo systemctl enable patroni
sudo systemctl start patroni
Check cluster status:
# On any node
patronictl -c /etc/patroni/patroni.yml list
Creating Nexus Database
Connect to the master node and create the Nexus database:
-- Connect as postgres user
CREATE USER nexus WITH ENCRYPTED PASSWORD 'nexus-db-password';
CREATE DATABASE nexus OWNER nexus;
GRANT ALL PRIVILEGES ON DATABASE nexus TO nexus;
-- Create required extensions
\c nexus
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
Configuring Shared Storage
Nexus requires shared blob storage accessible by all nodes. Here's an NFS setup:
Setting up NFS Server
On your NFS server:
# Install NFS
sudo apt install -y nfs-kernel-server
# Create shared directory
sudo mkdir -p /nexus-shared/blobs
sudo chown -R nexus:nexus /nexus-shared
# Configure NFS exports
echo "/nexus-shared 10.0.1.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
# Export the filesystem
sudo exportfs -a
sudo systemctl restart nfs-kernel-server
Mounting NFS on Nexus Nodes
On each Nexus node:
# Install NFS client
sudo apt install -y nfs-common
# Create mount point
sudo mkdir -p /opt/sonatype/sonatype-work/nexus3/blobs
# Mount NFS share
sudo mount -t nfs 10.0.1.100:/nexus-shared/blobs /opt/sonatype/sonatype-work/nexus3/blobs
# Add to fstab for permanent mounting
echo "10.0.1.100:/nexus-shared/blobs /opt/sonatype/sonatype-work/nexus3/blobs nfs defaults 0 0" | sudo tee -a /etc/fstab
Installing and Configuring Nexus Repository
Installing Nexus Repository Pro
On each Nexus node:
# Create nexus user
sudo useradd -r -m -c "nexus role account" -d /opt/sonatype -s /bin/false nexus
# Download and extract Nexus Repository Pro
cd /opt
sudo wget https://download.sonatype.com/nexus/3/nexus-3.45.0-01-unix.tar.gz
sudo tar -xzf nexus-3.45.0-01-unix.tar.gz
sudo ln -s nexus-3.45.0-01 nexus
sudo chown -R nexus:nexus /opt/sonatype /opt/nexus*
# Install your license
sudo cp nexus-professional.lic /opt/sonatype/sonatype-work/nexus3/
Configuring Nexus for HA
Create the Nexus configuration:
# /opt/nexus/etc/nexus-default.properties
nexus-context-path=/
# Clustering configuration
nexus.clustered=true
nexus.hazelcast.discovery.isEnabled=true
# Database configuration
nexus.datastore.enabled=true
nexus.datastore.nexus.type=jdbc
nexus.datastore.nexus.jdbcUrl=jdbc:postgresql://10.0.1.21:5432/nexus?targetServerType=primary
nexus.datastore.nexus.username=nexus
nexus.datastore.nexus.password=nexus-db-password
# Hazelcast clustering
nexus.hazelcast.discovery.type=tcp
nexus.hazelcast.discovery.tcp.members=10.0.1.30:5701,10.0.1.31:5701,10.0.1.32:5701
Advanced Clustering Configuration
Create a custom Hazelcast configuration:
<!-- /opt/nexus/etc/hazelcast-network.xml -->
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.hazelcast.com/schema/config
http://www.hazelcast.com/schema/config/hazelcast-config-4.0.xsd">
<network>
<port auto-increment="true" port-count="100">5701</port>
<join>
<multicast enabled="false"/>
<tcp-ip enabled="true">
<member>10.0.1.30</member>
<member>10.0.1.31</member>
<member>10.0.1.32</member>
</tcp-ip>
</join>
</network>
<partition-group enabled="false"/>
</hazelcast>
Reference this file in your nexus-default.properties:
nexus.hazelcast.configurationFile=etc/hazelcast-network.xml
Creating Nexus Service
Create a systemd service:
# /etc/systemd/system/nexus.service
[Unit]
Description=nexus service
After=network.target
[Service]
Type=forking
LimitNOFILE=65536
ExecStart=/opt/nexus/bin/nexus start
ExecStop=/opt/nexus/bin/nexus stop
User=nexus
Restart=on-abort
TimeoutSec=600
[Install]
WantedBy=multi-user.target
Start Nexus on all nodes:
sudo systemctl enable nexus
sudo systemctl start nexus
Setting Up Load Balancer
Configure HAProxy for load balancing:
# /etc/haproxy/haproxy.cfg
global
daemon
maxconn 4096
log stdout local0
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
option httplog
frontend nexus_frontend
bind *:80
bind *:443 ssl crt /etc/ssl/certs/nexus.pem
redirect scheme https if !{ ssl_fc }
default_backend nexus_backend
backend nexus_backend
balance roundrobin
option httpchk GET /service/rest/v1/status
http-check expect status 200
server nexus1 10.0.1.30:8081 check inter 5s
server nexus2 10.0.1.31:8081 check inter 5s
server nexus3 10.0.1.32:8081 check inter 5s
backend nexus_docker
balance roundrobin
option httpchk GET /v2/
server nexus1 10.0.1.30:8082 check inter 5s
server nexus2 10.0.1.31:8082 check inter 5s
server nexus3 10.0.1.32:8082 check inter 5s
Monitoring and Troubleshooting
Health Check Scripts
Create monitoring scripts to verify cluster health:
#!/bin/bash
# /usr/local/bin/check-nexus-cluster.sh
NEXUS_NODES=("10.0.1.30:8081" "10.0.1.31:8081" "10.0.1.32:8081")
HEALTHY_NODES=0
for node in "${NEXUS_NODES[@]}"; do
if curl -sf "http://${node}/service/rest/v1/status" > /dev/null; then
echo "✓ Node $node is healthy"
((HEALTHY_NODES++))
else
echo "✗ Node $node is unhealthy"
fi
done
if [ $HEALTHY_NODES -ge 2 ]; then
echo "Cluster is healthy ($HEALTHY_NODES/3 nodes up)"
exit 0
else
echo "Cluster is unhealthy ($HEALTHY_NODES/3 nodes up)"
exit 1
fi
PostgreSQL Cluster Monitoring
#!/bin/bash
# Check PostgreSQL cluster status
patronictl -c /etc/patroni/patroni.yml list
# Check replication lag
psql -h 10.0.1.21 -U nexus -d nexus -c "SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication;"
Common Issues and Solutions
Problem: Nodes can't join the cluster Solution: Check firewall rules. Ensure ports 5701 (Hazelcast) and 8081 (Nexus) are open between nodes.
Problem: Split-brain scenarios Solution: Always use odd numbers of nodes (3, 5, 7) and proper quorum settings in your clustering configuration.
Problem: Slow performance Solution: Monitor your shared storage latency. NFS can be a bottleneck—consider moving to a more performant shared storage solution like AWS EFS or Ceph.
Problem: Database connection issues Solution: Verify your PostgreSQL cluster is healthy and that all Nexus nodes can reach the current master.
Testing Your HA Setup
Once everything's running, test your setup:
- Upload an artifact to verify basic functionality
- Stop one Nexus node and verify artifacts are still accessible
- Simulate PostgreSQL failover and verify Nexus handles it gracefully
- Test load balancer failover by stopping multiple nodes
Your HA Nexus Repository setup is now ready for production. Remember to monitor it closely and practice your disaster recovery procedures regularly. A setup is only as good as your team's ability to operate it when things go wrong.
The investment in setting up HA properly will pay dividends when your artifact repository just works, even when individual components fail. Your future self (and your teammates) will thank you.
Was this article helpful?
DevOps Educator
I break down complex DevOps concepts into things you can actually understand and use on Monday morning. Whether you're switching careers or leveling up, I write the guides I wish I had when I started.
Related Articles
Nexus Repository 503 Service Unavailable After JVM Heap Exhaustion: Diagnosis And Fix
If you've ever stared at a 503 error from Nexus Repository Manager right before a critical deployment, you know the panic. Your CI/CD pipeline is blocked,...
Nexus Repository Docker Registry Proxy Configuration For Air-Gapped Environments
Air-gapped environments are a reality for many organizations dealing with sensitive data, regulatory compliance, or high-security requirements. When you ca...
Nexus Repository Cleanup Policies: Stop Your Disk From Filling Up
Configure Nexus Repository cleanup policies to automatically remove old snapshots, unused artifacts, and stale Docker layers before your disk fills up.
Artifact Repositories in CI/CD: Push, Pull, and Promote
Integrate Nexus and Artifactory with Jenkins, GitHub Actions, and GitLab CI — push artifacts, pull dependencies, and implement promotion workflows.
Nexus Repository Manager: Setup and Configuration Guide
Deploy Nexus Repository Manager, configure hosted and proxy repositories for Docker, npm, Maven, and PyPI, and set up cleanup policies and access control.
Nexus Repository Manager: Setup, Docker Registry, and Maven/npm Proxy
How to install and configure Sonatype Nexus Repository Manager 3 — setting up hosted, proxy, and group repositories for Docker, Maven, and npm, with access control and cleanup policies.