A New Era for PostgreSQL Backups: Exploring pg_hardstorage
Today we are going to tackle a classic open-source challenge that recently shook up our community, followed by an exciting new solution.
As a Zabbix partner, my company frequently designs 100% functional, highly available (HA) architectures. Even if Zabbix itself is running standalone, we always recommend a robust backend on PostgreSQL. For years, we’ve trusted PostgreSQL distributed across multiple nodes to guarantee resilience, typically relying on a stack that includes Patroni for cluster orchestration, etcd for quorum, and pgBackRest for backups.
However, earlier this year, a bit of a "pata-track" (a disaster) happened in the PostgreSQL ecosystem. Let's look at what went down and explore a brilliant new alternative.
The pgBackRest Scare and the Community's Response
Around April 26th, the maintainer of pgBackRest—a pillar of the Postgres ecosystem for over half a decade—announced the project's end-of-life (EOL). For anyone maintaining large-scale databases or Kubernetes environments, this created a massive void. Panic ensued, and the community went a bit crazy.
Fortunately, the open-source spirit prevailed. By May 18th, major sponsors like Amazon, Supabase, and Percona stepped up to fund the developer, and pgBackRest resumed its evolution. But during that month of uncertainty, many of us started wondering: Could we do this better? Is it time for a more modern approach?
Enter pg_hardstorage: A Modern Pull-Based Alternative
Our friends at Cybertec (one of the few companies offering enterprise PostgreSQL support, and our partner for Italy) decided to answer that question. They released pg_hardstorage, a brand-new, open-source backup tool designed to modernize how we protect PostgreSQL data.
Unlike the script-heavy, push-based paradigm of older tools, pg_hardstorage relies on PostgreSQL's native streaming replication. It completely decouples the backup server from the database nodes, pulling data seamlessly without the need for complex SSH key meshes.
Key Features at a Glance
- Native Replication Streaming: No more
archive_commandpushing data. It integrates directly with Postgres protocols. - Deduplication & Compression: It moves away from the traditional full/incremental/differential chains. Every backup is a "full" backup, but heavily deduplicated and compressed using Content Addressable Storage (CAS).
- Default Encryption: Everything is encrypted at rest using an AES-256-GCM-SIV envelope. (More on this later—don't lose your keys!)
- Cryptographic Audit Log: It uses a hash-chained Merkle tree (similar to a blockchain ledger) called the
audit_anchorto ensure backups haven't been tampered with by ransomware or bad actors. - Simplified Architecture: You only need to install the binary on the backup machine. It automatically polls the Patroni REST API to find the active leader.
Architectural Shift: Simplifying the Cluster
In a traditional pgBackRest setup across a 3-node cluster, you needed SSH key exchanges between all nodes and archive commands firing constantly. With pg_hardstorage, the design is brilliantly simple.
We use three nodes: two hosting PostgreSQL in HA (Leader and Streaming nodes) and a third dedicated to etcd quorum and backups. The backup node simply reaches out via standard Postgres connections. No SSH mesh required!
Step-by-Step Implementation Guide
I tested this on Rocky Linux 10. While the official documentation felt a bit like "AI vibe coding" in places (sorry, Cybertec friends!), I managed to get it running smoothly. Here is how you can set it up in a Patroni HA environment.
1. Preparing PostgreSQL and Patroni
First, we need to ensure our database doesn't crash if the backup node goes offline. On your Leader Node, edit the Patroni configuration (patronictl edit-config) to set a safety limit:
postgresql:
parameters:
max_slot_wal_keep_size: 50GB
Next, update your pg_hba.conf to allow the backup node to stream WALs and probe the system:
# Required for base backups and WAL streaming
host replication replicator 192.168.8.237/32 md5
# Required for system probes and leader detection
host all replicator 192.168.8.237/32 md5
2. Installation and Initialization
On your dedicated Backup Node, install the RPM package. Once installed, we initialize the repository. Note how we point it to the local mount point (/pg-backups/zabbix) and define the Postgres connection:
pg_hardstorage init --yes --deployment prod \
--pg-connection 'postgres://replicator:MY_PASSWORD@192.168.8.178:5432/postgres' \
--repo file:///pg-backups/zabbix
To ensure the backup agent automatically follows the active leader during a Patroni failover, we link the Patroni URLs:
pg_hardstorage deployment edit prod \
--patroni-url "http://192.168.8.178:8008,http://192.168.8.156:8008"
3. Automation and The Cryptographic Audit Anchor
The configuration file (pg_hardstorage.yaml) handles scheduling. You can easily set it to backup every 6 hours and rotate daily. But the standout feature is the audit_anchor.
By scheduling the audit anchor every hour, the tool mathematically "seals" the current state of the ledger. If a bad actor deletes backup files to hide their tracks, the tool instantly detects the corruption and alerts you.
4. Setting up Systemd Services
Unlike pgBackRest, which relied heavily on cron jobs, pg_hardstorage uses two clean Systemd services:
pg_hardstorage-wal.service: Handles real-time continuous WAL archiving (streaming).pg_hardstorage-agent.service: Handles the scheduled full backups.
5. Cryptographic Security (Mandatory Action!)
CRITICAL WARNING: The repository is encrypted by default. If your backup node dies and you lose the Key Encryption Key (KEK), your backups are permanently unreadable. Immediately back up this file to a secure, off-server vault:
cat /var/lib/pg_hardstorage/.config/pg_hardstorage/keyring/kek.bin
Testing Backups and Restores
To check the health of your setup, you can run pg_hardstorage doctor prod. To see your backups, simply run pg_hardstorage list prod.
When I tested restores, I ran into a few standard Linux permission denied errors because I didn't set up the target directory correctly at first. Always ensure your target directory is empty and owned by the pgbackup user!
To perform a Point-in-Time Recovery (PITR) to a temporary directory for testing, the command is delightfully simple:
pg_hardstorage restore prod "2026-06-30T10:00:00Z" --target /tmp/recovery_test
Final Thoughts
Is pg_hardstorage fully enterprise-ready to replace pgBackRest everywhere tomorrow? Maybe not quite yet—it’s a young project, and there are still a few bugs and documentation quirks to iron out. However, the architectural improvements, the removal of SSH dependencies, and the modern deduplication approach make it an incredibly promising tool, especially for Kubernetes and cloud-native environments.
I highly encourage you to spin it up in a lab, test it out, and give the Cybertec team feedback on their GitHub repository. That’s how open-source thrives!
Let me know in the comments what you think of this new solution! Have you tried it yet?
Thank you for reading, and I'll see you next week with another video. Greetings from Dimitri!
📌 Subscribe to my YouTube Channel: Quadrata
📌 Join our ZabbixItalia Community: ZabbixItalia Telegram Channel