High Availability
Truss talks to Postgres over a single DATABASE_URL. That means HA is a property
of the Postgres you point it at, not of Truss itself, which is exactly what you
want: use whatever database high-availability story you already trust.
What the default deployment gives you
Section titled “What the default deployment gives you”Both shipped deployments run a single Postgres instance:
- Docker Compose (
docker-compose.selfhosted.yml) , onepostgrescontainer. - Helm chart (
charts/truss) , one PostgresStatefulSet,replicas: 1.
This is deliberate: it runs anywhere, it’s cheap, and it’s the right default for a homelab, a single VPS, or an evaluation. It has no failover, if that Postgres goes down, Truss is down until it comes back. Take regular backups (see Branching & Backups).
Option 1 , managed Postgres (recommended for most)
Section titled “Option 1 , managed Postgres (recommended for most)”The simplest path: don’t self-manage HA at all. Point DATABASE_URL at a managed
Postgres (Amazon RDS / Aurora, Cloud SQL, Neon, Supabase, Crunchy Bridge). They
handle replication, automatic failover, backups, and PITR for you.
DATABASE_URL=postgres://user:pass@your-managed-host:5432/truss?sslmode=requireNothing else in Truss changes. This is the least operational burden and the safest choice unless you specifically want to run the database yourself.
Option 2 , run Postgres under an operator (self-managed HA)
Section titled “Option 2 , run Postgres under an operator (self-managed HA)”If you want HA on your own Kubernetes cluster, run Postgres under a replication
operator such as CloudNativePG (CNPG) and point
DATABASE_URL at the operator’s read-write Service. CNPG gives you streaming
replicas and operator-driven automatic failover with no extra tooling.
# a CloudNativePG Cluster (NOT the Truss chart), e.g. instances: 3apiVersion: postgresql.cnpg.io/v1kind: Clustermetadata: name: truss-postgresspec: instances: 3 # 1 primary + 2 streaming replicasCNPG then manages three Services , *-rw (primary, use this in DATABASE_URL),
*-ro (replicas), *-r (any). It also pairs cleanly with a PgBouncer Pooler
(type: rw), which follows the primary automatically.
What failover does
Section titled “What failover does”If the primary becomes unhealthy, the operator:
- Promotes the most up-to-date replica to primary.
- Repoints the
-rwService at the new primary automatically. - Rejoins the old primary as a replica once it recovers.
Because Truss and any pooler connect through the -rw Service (not a pod), they
follow the new primary with no config change , a brief blip during promotion,
then reconnect.
Async vs sync replicas
Section titled “Async vs sync replicas”Replication is asynchronous by default: fast, but a failover can lose the last few transactions that hadn’t reached the promoted replica (a small RPO window). For zero data loss, require a synchronous replica (trades a little write latency):
spec: instances: 3 postgresql: synchronous: method: any number: 1 # at least one replica must confirm each commit