Deploy PostgreSQL Highly Available Cluster
Railway

Deploy PostgreSQL Highly Available Cluster

Self-host Postgres with zero downtime, auto failover using Patroni & etcd

Deploy PostgreSQL Highly Available Cluster

Etcd

/var/lib/etcd

/var/lib/etcd

/var/lib/etcd

Postgres

/var/lib/postgresql/data

/var/lib/postgresql/data

/var/lib/postgresql/data

Deploy and Host PostgreSQL High Availability (Patroni) on Railway

Deploy PostgreSQL with automatic failover using Patroni on Railway. This template provisions a production-ready, 7-service HA cluster: 3 etcd nodes for distributed consensus, 3 PostgreSQL nodes managed by Patroni for streaming replication and automatic leader election, and an HAProxy load balancer that routes read-write traffic to the current primary and read-only queries to replicas.

Self-host PostgreSQL HA with Patroni on Railway to get sub-30-second automatic failover, zero-downtime maintenance windows, and horizontal read scaling — all without managing bare-metal servers or writing custom failover scripts.

Getting Started with PostgreSQL HA (Patroni) on Railway

After deployment completes, all seven services will show as active in your Railway dashboard. Patroni automatically elects a primary node (leader) and configures the other two PostgreSQL nodes as streaming replicas.

Connect to your cluster through the HAProxy TCP proxy endpoint. The read-write port (5432) routes to the current primary, while read-only port (5433) is available internally via haproxy.railway.internal:5433. Use the connection string from your Railway project variables:

psql "postgresql://railway:@monorail.proxy.rlwy.net:/railway"

Verify cluster health by checking Patroni's REST API on any postgres node at port 8008, or monitor HAProxy stats via the HTTP domain. To test failover, stop the primary node — Patroni will promote a replica within 20–30 seconds, and HAProxy will automatically reroute traffic.

About Hosting PostgreSQL HA with Patroni

Patroni is a Python-based high availability solution for PostgreSQL that automates cluster management, failover, and replication using a distributed consensus store (etcd, Consul, or ZooKeeper). Originally created by Zalando, it is the most widely adopted PostgreSQL HA framework in production environments.

Key features:

  • Automatic failover with configurable TTL and loop wait — RTO consistently 20–30 seconds
  • Streaming replication with synchronous or asynchronous modes
  • REST API for cluster state inspection and manual switchover/failover
  • etcd-backed consensus — no split-brain scenarios
  • HAProxy integration — transparent connection routing based on Patroni health checks
  • Self-healing — automatically reinitializes failed nodes from the current primary

The architecture uses etcd (3-node quorum) for leader election, Patroni as a sidecar daemon on each PostgreSQL node, and HAProxy for TCP load balancing based on Patroni's health endpoints.

Why Deploy PostgreSQL HA (Patroni) on Railway

  • One-click 7-service cluster — no infrastructure provisioning or manual configuration
  • Private networking — all inter-service communication stays on Railway's internal network
  • Persistent volumes — each PostgreSQL and etcd node gets dedicated storage
  • Automatic failover — Patroni handles leader election and replica promotion
  • TCP proxy — external access to PostgreSQL without VPN or SSH tunnels

Common Use Cases for Self-Hosted PostgreSQL HA

  • Production databases requiring zero-downtime — SaaS platforms, e-commerce, financial systems where any downtime means lost revenue
  • Read-heavy workloads — distribute SELECT queries across replicas via HAProxy's read-only port while writes go to the primary
  • Compliance-sensitive data — self-hosted PostgreSQL with full control over data residency, encryption, and access
  • Blue-green deployments — perform rolling PostgreSQL upgrades with Patroni switchover, zero client-side changes needed

Dependencies for PostgreSQL HA (Patroni) on Railway

  • PostgreSQL Patroni (x3) — ghcr.io/railwayapp-templates/postgres-ha/postgres-patroni:latest — PostgreSQL 16 with Patroni HA daemon
  • etcd (x3) — ghcr.io/railwayapp-templates/postgres-ha/etcd:latest — Distributed key-value store for cluster consensus
  • HAProxy (x1) — ghcr.io/railwayapp-templates/postgres-ha/haproxy:latest — TCP load balancer with Patroni-aware health checks

Deployment Dependencies

Hardware Requirements for Self-Hosting PostgreSQL HA with Patroni

ComponentMinimumRecommended
CPU (per node)0.5 vCPU1+ vCPU
RAM (per postgres node)512 MB1–2 GB
RAM (per etcd node)256 MB512 MB
RAM (haproxy)128 MB256 MB
Storage (per postgres node)1 GB5–50 GB
Storage (per etcd node)500 MB1–2 GB
Total cluster RAM~2.5 GB~6 GB

Self-Hosting PostgreSQL HA with Patroni Using Docker

The fastest way to self-host a Patroni cluster is with Docker Compose. Here's a minimal 3-node setup:

# docker-compose.yml (simplified)
services:
  etcd-1:
    image: ghcr.io/railwayapp-templates/postgres-ha/etcd:latest
    environment:
      ETCD_NAME: etcd-1
      ETCD_INITIAL_CLUSTER: "etcd-1=http://etcd-1:2380"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
      ETCD_LISTEN_PEER_URLS: "http://0.0.0.0:2380"

  postgres-1:
    image: ghcr.io/railwayapp-templates/postgres-ha/postgres-patroni:latest
    environment:
      PATRONI_SCOPE: my-cluster
      PATRONI_NAME: postgres-1
      PATRONI_ETCD3_HOSTS: etcd-1:2379
      PATRONI_SUPERUSER_USERNAME: postgres
      PATRONI_SUPERUSER_PASSWORD: secretpass
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - pg1_data:/var/lib/postgresql/data

  haproxy:
    image: ghcr.io/railwayapp-templates/postgres-ha/haproxy:latest
    environment:
      POSTGRES_NODES: "postgres-1:5432:8008"
    ports:
      - "5432:5432"

volumes:
  pg1_data:

For a production 3-node cluster, replicate the etcd and postgres services with unique names and add them to the ETCD_INITIAL_CLUSTER and POSTGRES_NODES variables.

# Connect to the cluster via HAProxy
psql -h localhost -p 5432 -U railway -d railway

How Much Does PostgreSQL HA with Patroni Cost to Self-Host?

Patroni, etcd, HAProxy, and PostgreSQL are all fully open source with no licensing fees. The entire stack is free to use in production.

On Railway, you pay only for infrastructure — compute and storage for the 7 services. A minimal cluster runs on approximately $15–25/month depending on usage. The main cost drivers are persistent storage for PostgreSQL data and RAM for the postgres nodes.

Patroni vs Repmgr vs Pgpool for PostgreSQL High Availability

FeaturePatroniRepmgrPgpool-II
Automatic failoverYes (consensus-based)Yes (with witness)Yes (watchdog)
Split-brain preventionStrong (etcd/Consul)ModerateModerate
Connection poolingNo (use PgBouncer)NoBuilt-in
Read load balancingVia HAProxyManualBuilt-in
Setup complexityModerate–HighLow–ModerateModerate
Production adoptionHighestModerateModerate
Failover time (RTO)20–30 seconds30–60 seconds10–30 seconds

Patroni is the most robust choice for production HA, especially in containerized environments. Its consensus-based approach via etcd eliminates split-brain scenarios — the most dangerous failure mode in database clustering.

FAQ

What is Patroni and why use it for PostgreSQL high availability? Patroni is a Python-based HA framework that automates PostgreSQL cluster management, failover, and replication. It uses a distributed consensus store (etcd) to prevent split-brain scenarios and provides automatic leader election with sub-30-second failover times.

What does this Railway template deploy for PostgreSQL HA? This template deploys 7 services: 3 etcd nodes for distributed consensus, 3 PostgreSQL nodes managed by Patroni (1 primary + 2 replicas with streaming replication), and 1 HAProxy instance for TCP load balancing. All services communicate over Railway's private network.

Why does PostgreSQL HA need three etcd nodes on Railway? etcd requires a quorum (majority) to make decisions. With 3 nodes, the cluster tolerates 1 node failure while maintaining consensus. This prevents split-brain — where two nodes both think they're the primary — which is the most dangerous failure mode in database clustering.

How does automatic failover work with self-hosted Patroni? When the primary PostgreSQL node becomes unavailable, Patroni detects the failure via its health check loop (configurable TTL). The remaining nodes use etcd to elect a new leader. The promoted replica begins accepting writes, and HAProxy automatically routes traffic to the new primary — all within 20–30 seconds.

Can I connect my existing application to Patroni PostgreSQL on Railway? Yes. Connect through the HAProxy TCP proxy endpoint using a standard PostgreSQL connection string. Your application connects to HAProxy, which transparently routes to the current primary. No application-level changes are needed — HAProxy handles failover routing automatically.

What happens to data during a PostgreSQL failover on Railway? Patroni uses PostgreSQL streaming replication, so replicas are continuously synchronized with the primary. During failover, committed transactions on the primary are preserved on the replicas. Uncommitted transactions at the exact moment of failure may be lost (configurable with synchronous replication for zero data loss).


Template Content

More templates in this category

View Template
Foundry Virtual Tabletop
A Self-Hosted & Modern Roleplaying Platform

Lucas
View Template
Letta Code Remote
Run a Letta Code agent 24/7. No inbound ports, just deploy.

Letta
View Template
(v1) Simple Medusa Backend
Deploy an ecommerce backend and admin using Medusa

Shahed Nasser