pg_hardstorage

v1.0 released · Apache 2.0 · open source · PostgreSQL 15–18

pg_hardstorage is an open-source PostgreSQL backup tool — built so something as fundamental as your recovery story stays code you can read, run, and rely on. WAL streaming over the replication protocol, content-addressed storage where every backup restores on its own, and a design that values boring, verifiable reliability over cleverness. Originally developed by CYBERTEC, now a community project.

0 Backup Chains to Break

AES-256 Encryption On by Default

Apache 2.0 Open-Source Licence

"Backup software is plumbing. Plumbing you can't inspect is a leak waiting to happen."

KMS & encryption

AWS KMS

GCP KMS

Azure Key Vault

Vault Transit

PKCS#11 / HSM (in progress)

Object storage

Filesystem

Amazon S3

Google Cloud Storage

Azure Blob

SFTP

PostgreSQL you run yourself

Self-managed PostgreSQL 15-18

Patroni clusters

CloudNativePG

All integrations are shipped in-tree. Tier-2 plugins (gRPC over stdio) let you add your own — see architecture for the plugin contract.

Open source under Apache 2.0

FIPS build variant, SCIM, the hash-chained audit log, KMS-backed encryption, and compliance reporting are all developed in the open. Read every line on GitHub before you trust it with your WAL stream.

Community-governed

Public roadmap, public issues, DCO sign-off on every commit. Bug reports land best as runnable testkit scenarios — your green-then-red commit becomes our regression test. Anyone can read, anyone can patch, anyone can fork.

Outlive your vendor

If we disappear tomorrow, your repository is still readable. The wire format is documented and schema-versioned with a 24-month backward-compatibility commitment. Every chunk is content- addressed; every manifest is plain JSON. Your data stays yours.

"Backup is the one piece of infrastructure where 'trust us, it's proprietary' is the wrong answer. pg_hardstorage is engineered to be inspected — by you, by your auditors, by anyone."

Data plane

WAL via the replication protocol

The agent connects to PostgreSQL the same way a streaming replica does — a libpq connection, nothing else. No SSH. No archive_command. No host access. That is why a bare-metal server, a Patroni cluster, and PostgreSQL behind a Kubernetes operator all take the same setup: there's no special privilege, just a replication-role user that can run BASE_BACKUP.

Repository

Content-addressed dedup

FastCDC chunker with page-aligned splits. Every chunk keyed by its plaintext SHA-256, so the chunk store itself has no chains — a chunk is shared by hash, never copied. A repeat backup deduplicates against the deployment's existing chunks, so unchanged data costs almost nothing in storage. (PG 17 incremental backups still record their parent, and retention keeps that parent pinned.)

Encryption

AES-256-GCM envelope, FIPS-ready

A per-backup data key (DEK) encrypts every chunk with AES-256-GCM under a unique random nonce; the DEK is wrapped by your KMS. AES-256-GCM by default; a BoringCrypto FIPS build variant is available. Crypto-shred by destroying the wrapping key — Article 17 compliance in one command.

Pluggable

KMS & storage backends, pluggable

Keys: AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault Transit, and a local keyring (a PKCS#11 / HSM plugin is in progress). Storage: filesystem, S3, GCS, Azure Blob, SFTP and SCP. Tier-2 plugins ride a stable gRPC-over-stdio protocol — write your own in any language that speaks gRPC.

High availability

Patroni-aware failover

Four cooperating mechanisms — Patroni permanent_slots, PG 17 synced slots, recreate-on-detection, and the gap auditor — keep WAL streaming through leader switches.

Recovery

Point-in-time, in plain English

--to "5 minutes ago", --to-lsn 0/3000028, --to-name <name>. The orchestrator picks the latest full whose stop-LSN precedes the target, replays WAL, applies timeline switches, and prints a projected RTO before it starts.

Verification

Sandboxed full-restore verify

Two verifier sandboxes — Docker by default, Firecracker microVM with the -tags firecracker build. Restore into a throwaway PG and run pg_verifybackup, then tear it down. A backup you didn't restore is a backup you don't have.

3am operator surface

LLM-assisted, not LLM-controlled

Optional. Read-only by default. Every suggestion footnoted to its source tool call, every session hash-chained into the audit log. Advise+execute is opt-in and gated by a five-stage safety stack. The 3am operator gets help — the 3am operator does not get an autonomous agent with shell on the data directory.

Output

Structured everywhere

Every command supports --output json or --output ndjson with the pg_hardstorage.v1 schema. 14 sinks · 11 renderers · OpenTelemetry traces · Prometheus metrics on pg_hardstorage_*. Wire format committed to 24-month back-compat.

Most native

Kubernetes

PostgreSQL behind a Kubernetes operator is standard Postgres in a pod — pg_hardstorage backs it up over the replication protocol like any instance you run yourself. Verified end-to-end against CloudNativePG: backup, verify, and restore all round-trip cleanly. Run it as a CronJob or a Deployment.

  • CloudNativePG — backup/verify/restore verified
  • Runs as a CronJob or a Deployment
  • Connects over the standard replication protocol
  • In-tree Helm chart; no operator plugin yet

Bare-metal Linux

RPM and .deb packaging for RHEL, Rocky, AlmaLinux, Fedora (≥ 9), Debian, Ubuntu. systemd units in deploy/systemd/; a one-liner ./compile.sh for custom builds.

  • RPM / .deb / systemd units
  • FHS / XDG paths respected
  • Distroless container variant

Containers

The repository ships deploy/docker/Dockerfile — a small static image you build and host yourself. The release pipeline (see .goreleaser.yaml) cosign-signs artefacts and emits an SPDX SBOM.

  • Docker / Podman / containerd
  • Static binary · runs as nonroot
  • Cosign-signed releases · SBOM

Air-gapped

Repo bundle export/import for moving backups across security boundaries. Air-gap policy refuses any plugin that performs network I/O. Runbook-driven cold-start from offline media.

  • Repo bundle export / import
  • Network-deny policy mode
  • Offline KMS support

FIPS / Compliance

A BoringCrypto FIPS build variant (make build-fips). Releases are cosign-signed with an SPDX SBOM. The hash-chained audit log can be anchored to a transparency log with audit anchor.

  • FIPS build variant
  • Cosign-signed releases · SBOM
  • Hash-chained, anchorable audit log
  • Per-core licensing — your DB grows, the bill grows with it
  • Backup format you can't decode without the vendor's binary
  • Roadmap controlled by a single owner — your priorities don't matter
  • Closed internals you cannot read, audit, or fix yourself
  • SSH access and a host-side archive_command to set up
  • Acquisition risk: vendor gets bought, terms change overnight

VS

  • Apache 2.0 licensed — read, run, audit, and fork the source
  • Documented wire format · plain-JSON manifests · 24-month back-compat
  • Public roadmap · DCO-signed PRs · anyone can fork and ship a feature
  • FIPS, SCIM, and the audit chain are developed in the open
  • Replication-protocol data plane — no SSH or host-side hook needed
  • If we vanish tomorrow, your repo is still readable

Apache 2.0 Open-source licence you can read and fork

Open Public roadmap, issues, and development

Zero Lock-in — your repo, your format

01

Stream WAL via the replication protocol

The agent opens a libpq connection to PostgreSQL, claims a persistent physical replication slot, and pulls WAL the same way a streaming replica does. Slot continuity survives Patroni failovers; gaps are detected and surfaced explicitly.

02

Chunk → encrypt → deduplicate → store

FastCDC chunker with page-aligned splits. Each chunk encrypted with the per-backup DEK under a unique nonce. SHA-256 over plaintext gives stable content addressing — dedup survives compression and encryption-setting changes. Object lands in S3, GCS, Azure Blob, filesystem, or SFTP.

03

Restore: pull, replay, verify

Restore picks the latest full whose stop-LSN precedes your target, pulls the chunks, replays WAL up to the LSN or natural-language time, applies timeline switches, and runs pg_verifybackup. An optional sandboxed verify restores into a throwaway PG and re-runs pg_verifybackup there before you trust it.

RPO

Continuous WAL

The agent streams WAL continuously over a physical slot, shrinking RPO to seconds. Synchronous sync-target mode (RPO=0) is on the roadmap, not yet shipped.

RTO

Plan before you restore

Restore is bandwidth-bound; --preview prints a projected RTO before it starts. Parallel chunk fetching is a planned optimisation — restore is single-stream today.

PITR

Natural-language time

--to "yesterday 9pm", --to-lsn 0/3000028, or --to-name <name>. Preview the plan before it runs.

GDPR Art. 17

Right to erasure — crypto-shred

  • One command: kms shred --repo R (approval-gated)
  • Destroying the wrapping key ends plaintext recoverability
  • Audit-chain entry is the compliance artefact
  • Bytes stay on disk — no rewrite required

SOC 2 / ISO 27001

Audit evidence, on demand

  • Hash-chained Merkle audit log
  • Anchored to Rekor or a customer-managed log
  • JSON + Markdown reports map events to control IDs
  • Signed evidence bundles via audit export-bundle

HIPAA / PCI DSS

Healthcare & payment data

  • Encrypted at rest under your KMS
  • n-of-m approvals on destructive operations
  • Legal-hold mechanism with audit-logged add/remove
  • Per-deployment data-residency policy enforcement

FIPS 140-2 / FedRAMP

US federal & regulated cloud

  • BoringCrypto FIPS build flavour
  • PKCS#11 / HSM key plugin (in progress)
  • WORM-mode storage (S3 Object Lock, Azure immutable)

Cosign-signed releases · SPDX SBOM

Cosign-signed releases · syft SBOM

Apache 2.0 — no CLA, just DCO sign-off

Maintainer's promise

The bar is "this would land in the project anyway." Tight, technical PR descriptions get tight, technical reviews. No CLA, no rights assignment — your DCO sign-off and Apache 2.0 is enough. Maintained by Hans-Jürgen Schönig at CYBERTEC PostgreSQL International, but owned by everyone who ships a patch.

DCO Not a CLA

Apache 2.0 Every line

Public Roadmap & issues

# Throwaway PG + agent + repo via Docker
./scripts/devcluster.sh up
# Take your first backup
pg_hardstorage backup db1 \
  --pg-connection postgres://... \
  --repo file:///var/lib/pg_hardstorage
# Restore it (dry-run preview first)
pg_hardstorage restore db1 latest \
  --repo file:///var/lib/pg_hardstorage \
  --target /tmp/r --preview
# Build (Go ≥ 1.26)
git clone https://github.com/cybertec-postgresql/pg_hardstorage
cd pg_hardstorage
./compile.sh
# Or via Make
make build         # bin/pg_hardstorage
make build-fips    # BoringCrypto variant
make build-pkcs11  # PKCS#11 variant
./bin/pg_hardstorage --help

Daily operations cheat-sheet

  • pg_hardstorage backup db1 --pg-connection … --repo …Take a backup right now
  • pg_hardstorage restore db1 latest --repo … --target … --to "5 minutes ago"Natural-language PITR
  • pg_hardstorage status db1 --repo …Deployment status
  • pg_hardstorage verify db1 latest --repo …Verify chunk hashes + manifest signature
  • pg_hardstorage doctor db1Connection + repository health
  • pg_hardstorage rotate db1 --repo … --keep-for 336h --applyRetention (dry-run without --apply)

Read the full documentation →

No. pg_hardstorage takes its base backup with the BASE_BACKUP replication-protocol command. Managed database services do not expose that command to customers — they do not let an external client run a physical base backup or attach a physical replica. So pg_hardstorage cannot back those services up, and we do not claim it can. It targets PostgreSQL you operate yourself: bare-metal and VM installs, Patroni clusters, and PostgreSQL behind a Kubernetes operator such as CloudNativePG.

PG 15, 16, and 17 are first-class. PG 18 is in the test matrix. PG 14 and earlier are out of scope — BASE_BACKUP non-exclusive mode and pg_backup_start / pg_backup_stop are PG 15-only APIs we rely on.

The pg_hardstorage open-source project is licensed under Apache 2.0. Compliance reporting, encryption, the audit chain, the FIPS build variant, and the LLM helper are all part of the project. It was originally developed by CYBERTEC PostgreSQL International GmbH and is now maintained with the community.

The short version: WAL via the replication protocol (works on managed PG), no chained incrementals (CAS dedup with no chain dependency), encryption / KMS / audit chain / WORM on by default. pgBackRest's strengths — production maturity at very large scale, mature operator integrations — are real, and we're explicit about the cases where each tool wins. Side-by-side migration paths exist for all three.

Yes. pg_hardstorage restore <deployment> --to "yesterday 9pm", or any other natural-language time, or --to-lsn 0/3000028, or --to-name <name>. The orchestrator picks the latest full whose stop_lsn precedes the target, replays WAL, and applies any timeline switches. --preview dry-runs the plan first.

The chunk store is content-addressed: every backup's manifest references the chunks it needs directly by SHA-256, and a chunk is shared, never copied. PG 17 incremental backups do record a parent backup, and retention pins that parent so it can't be pruned out from under its incrementals — but full backups stand alone, and there is no fragile differential chain to replay. More in the architecture page.

Restore is bandwidth-bound. Today the chunk fetch is single-stream, so end-to-end time tracks your link and storage throughput plus pg_verifybackup once the data dir is hydrated; parallel fetch is a planned optimisation. --preview prints a projected RTO (from a conservative throughput estimate) before kicking off.

Wherever you point the encryption plugin: AWS KMS, GCP KMS, Azure Key Vault, or HashiCorp Vault Transit (a PKCS#11 / HSM plugin is in progress). For single-host use, a local aes-256-gcm keyring directory works. KEK rotation re-wraps existing backups' DEKs without rewriting any chunks.

Yes. The audit log is hash-chained Merkle, periodically anchored to a transparency log (Rekor by default, customer-managed log on request). compliance report generates JSON + Markdown reports that map observed events to control IDs (PDF rendering is on the roadmap). Signed evidence bundles are produced via audit export-bundle.

Apache 2.0 means anyone can fork. The wire formats are documented and schema-versioned with a 24-month backward-compatibility commitment, so any fork can read your existing repository. Manifests are plain JSON; chunks are content-addressed. Your data is recoverable without the original vendor — by design.

Use the GitHub Security Advisories tab on the repository — an advisory is a private draft until disclosure. Don't open public issues for security findings. The disclosure policy is in SECURITY.md.

In-tree under docs/, and published at docs.pghardstorage.org. The site is built with MkDocs Material (make docs-build). The information architecture is Diátaxis: every page is either a tutorial, how-to, reference, or explanation. Plus seven named runbooks (R1–R7) for the disaster scenarios you'd otherwise discover at 3am.

Ready to read some code?

The repository is open.
The data plane is documented.

Star it on GitHub, file an issue, send a patch, or fork it and ship your own thing. That's the deal.

Read the original on pghardstorage.org ↗