Back to articles
Technology Insight

Building a Production-Ready PostgreSQL High Availability Cluster with Patroni, Etcd, and PgBouncer on 3 Budget VPS

June 3, 2026

Introduction: The Imperative of Database High Availability on a Budget

In the modern digital economy, data is the most critical asset of any enterprise. System downtime translates directly to financial loss, damaged reputation, and compromised user trust. For database administrators and infrastructure engineers, ensuring that PostgreSQL—one of the world's most advanced open-source relational databases—remains continuously available is a top priority.

Traditionally, achieving true High Availability (HA) required expensive enterprise-grade hardware or costly cloud-native managed solutions. However, by combining powerful open-source orchestration tools, businesses can build a robust, self-healing, production-ready PostgreSQL HA cluster on just three budget Virtual Private Servers (VPS). This guide walks you through the practical architecture and deployment of an HA cluster using Patroni for orchestration, Etcd for distributed consensus, and PgBouncer for efficient connection pooling.

1. The Architectural Blueprint: Component Breakdown

To design a system that tolerates hardware failures without human intervention, we must eliminate all Single Points of Failure (SPOFs). Our architecture relies on a specialized three-node topology, utilizing three distinct open-source technologies working in harmony.

The Core Components

  • PostgreSQL (The Database Engine): Provides the underlying relational database management system, utilizing streaming replication to sync data from the Primary node to Standby nodes.
  • Patroni (The Orchestrator): A Python-based template that transforms PostgreSQL into a dynamic, self-healing cluster. Patroni monitors the local database instance and updates the Distributed Configuration Store (DCS).
  • Etcd (The Distributed Configuration Store): A strongly consistent, distributed key-value store. Etcd manages the cluster state and handles leader election. A minimum of three nodes is mathematically required to achieve a quorum (majority agreement), preventing split-brain scenarios where two nodes simultaneously believe they are the leader.
  • PgBouncer (The Connection Pooler): A lightweight connection pooler for PostgreSQL. It reduces overhead by managing a pool of reusable connections and routes client traffic appropriately depending on whether a node is a primary or replica.

Node Allocation and IP Mapping

For this practical deployment, we allocate three budget VPS instances running a stable Linux distribution like Ubuntu 22.04 LTS or Debian 12:

  • Node 1 (vps-01): IP 10.0.0.11 — Runs Etcd, Patroni, PostgreSQL, PgBouncer
  • Node 2 (vps-02): IP 10.0.0.12 — Runs Etcd, Patroni, PostgreSQL, PgBouncer
  • Node 3 (vps-03): IP 10.0.0.13 — Runs Etcd, Patroni, PostgreSQL, PgBouncer

2. Step-by-Step Deployment Guide

Before proceeding, ensure all three nodes can communicate over a secure private network, have SSH keys configured, and have firewall rules adjusted to allow traffic on ports 2379/2380 (Etcd), 8008 (Patroni), 5432 (PostgreSQL), and 6432 (PgBouncer).

Step 2.1: Setting Up the Etcd Cluster

First, update system repositories and install Etcd on all three nodes:

sudo apt-get update && sudo apt-get install -y etcd-server etcd-client

Modify the /etc/etcd/etcd.yml configuration file on each node. The configuration must point to the specific node's IP and declare the peer addresses of the other two instances. Below is an example snippet for vps-01:

name: 'vps-01'
data-dir: '/var/lib/etcd/vps-01.etcd'
listen-peer-urls: '[http://10.0.0.11:2380](http://10.0.0.11:2380)'
listen-client-urls: '[http://10.0.0.11:2379](http://10.0.0.11:2379),[http://127.0.0.1:2379](http://127.0.0.1:2379)'
initial-advertise-peer-urls: '[http://10.0.0.11:2380](http://10.0.0.11:2380)'
advertise-client-urls: '[http://10.0.0.11:2379](http://10.0.0.11:2379)'
initial-cluster: 'vps-01=[http://10.0.0.11:2380](http://10.0.0.11:2380),vps-02=[http://10.0.0.12:2380](http://10.0.0.12:2380),vps-03=[http://10.0.0.13:2380](http://10.0.0.13:2380)'
initial-cluster-token: 'etcd-postgres-cluster-token'
initial-cluster-state: 'new'

Restart the Etcd service across all nodes and verify the cluster health using the command-line utility:

sudo systemctl restart etcd
etcdctl endpoint health --cluster

Ensure all endpoints return a healthy status before proceeding to the database layer.

Step 2.2: Installing and Configuring Patroni

Install PostgreSQL and Patroni dependencies. It is critical to stop and disable the default PostgreSQL service, as Patroni must have full operational custody over starting, stopping, and bootstrapping the database instances.

sudo apt-get install -y postgresql-15 patroni
sudo systemctl stop postgresql
sudo systemctl disable postgresql

Create the Patroni configuration file at /etc/patroni/patroni.yml. This file instructs Patroni how to interface with Etcd, sets up the bootstrap parameters for PostgreSQL replication, and configures authentication credentials. A condensed structure for the file includes:

scope: postgres-ha-cluster
namespace: /service
name: vps-01

etcd3:
  hosts:
    - 10.0.0.11:2379
    - 10.0.0.12:2379
    - 10.0.0.13:2379

restapi:
  listen: 10.0.0.11:8008
  connect_address: 10.0.0.11:8008

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    postgresql:
      use_pg_rewind: true
      use_slots: true
  initdb:
    - auth-host: md5
    - auth-local: trust
    - encoding: UTF8
  pg_hba:
    - host replication replicator 10.0.0.0/24 md5
    - host all all 0.0.0.0/0 md5

postgresql:
  listen: 10.0.0.11:5432
  connect_address: 10.0.0.11:5432
  data_dir: /var/lib/postgresql/15/main
  bin_dir: /usr/lib/postgresql/15/bin
  authentication:
    replication:
      username: replicator
      password: 'SecureReplicationPassword'
    superuser:
      username: postgres
      password: 'SecureMasterPassword'

Apply the configuration on all nodes, adjusting the node names and local IP addresses appropriately. Start the Patroni daemon service:

sudo systemctl start patroni
sudo systemctl enable patroni

To inspect the status of your newly formed cluster, utilize the Patroni control command line tool:

patronictl -c /etc/patroni/patroni.yml list

You should see one node dynamically elected as the Leader (Primary) with a running status, while the remaining two nodes are provisioned automatically as read-only Sync Standbys via streaming replication.

Step 2.3: Implementing PgBouncer for Load Balancing and Connection Pooling

Applications should not talk directly to PostgreSQL IPs in an HA cluster, because the Primary node can change during a failover. Instead, we use PgBouncer accompanied by automated routing logic.

Install PgBouncer on each node:

sudo apt-get install -y pgbouncer

Configure /etc/pgbouncer/pgbouncer.ini to manage connections effectively. To make PgBouncer route traffic seamlessly to whichever node is currently the leader, you can leverage Patroni's built-in HTTP REST API endpoints (specifically /primary and /replica) combined with an infrastructure load balancer like HAProxy or keepalived, or utilize automated script integrations that dynamically rewrite the PgBouncer configuration file upon failover events.

3. Validating Automatic Failover and Resilience

The true metric of a High Availability system is how it responds to unexpected infrastructure failures. We can conduct a controlled failure simulation to witness Patroni and Etcd in action.

  1. Log into your application dashboard and run a continuous write loop to monitor database availability.
  2. Simulate a catastrophic hardware fault on your Primary database instance by abruptly stopping the Patroni service or shutting down the virtual machine entirely: sudo systemctl stop patroni
  3. Monitor the logs on the remaining nodes. Within seconds, the Etcd lease will expire due to the lack of heartbeats.
  4. The remaining healthy nodes will trigger an election. The node with the most up-to-date transaction log (LSN) will be safely promoted to the new Leader.
  5. Patroni will issue a pg_rewind order to the old leader if it recovers, automatically demoting it to a Standby replica without manual intervention.

This automated sequence guarantees that data loss is minimized (or zero, depending on synchronous replication choices) and database downtime is reduced to mere seconds.

Conclusion and Best Practices for Production

Building a PostgreSQL High Availability cluster using Patroni, Etcd, and PgBouncer on 3 budget VPS instances provides an enterprise-grade solution at a fraction of the cost. However, maintaining production stability requires adhering to rigorous maintenance standards:

  • Automated Backups: HA protects against hardware failure, not human error. Implement solutions like pgBackRest or WAL-G for point-in-time recovery (PITR).
  • Monitoring and Alerts: Set up continuous monitoring tools like Prometheus and Grafana using the postgres_exporter to track replication lag, disk utilization, and Etcd health.
  • Resource Constraints: Since budget VPS environments share underlying physical hypervisors, closely monitor CPU steal time and disk I/O bottlenecks to ensure stable latency.

By leveraging this modern open-source stack, startups and growing digital businesses can deploy resilient, reliable infrastructure capable of scaling efficiently while maintaining strict financial discipline.

Building a Production-Ready PostgreSQL High Availability Cluster with Patroni, Etcd, and PgBouncer on 3 Budget VPS | DPTCloud