# What bkpdb does, in detail

> Everything bkpdb does, in detail.

URL: https://bkpdb.com/features/
Section: Features &middot; Illustrated

---


{{< stub "The Agent" >}}

<p style="max-width:42em;color:var(--mute);"><span class="dateline">Plate I.</span> A small static binary that lives on the database host. It listens on no ports. It speaks outbound mTLS to the control plane for heartbeats and configuration, talks to the database it tends, and to your storage destination. It does nothing else, and it requires no root and no system service to run.</p>

{{< plate title="The agent in situ" num="Fig. 1" >}}
                    ┌─ database host ─────────────────────────────┐
                    │                                             │
   ╔══════════╗     │   ┌──────────┐         ┌─────────────────┐  │
   ║ control  ║◀──mTLS──│  agent   │────────▶│   PostgreSQL    │  │
   ║  plane   ║     │   │          │         │   (read role)   │  │
   ╚══════════╝     │   └────┬─────┘         └─────────────────┘  │
                    │        │                                    │
                    │        │ stream:  pg_dump → zstd → encrypt  │
                    │        ▼                                    │
                    │   ┌──────────┐                              │
                    │   │  upload  │──────▶ your bucket / SFTP    │
                    │   └──────────┘                              │
                    │                                             │
                    └─────────────────────────────────────────────┘

         no inbound ports         no plaintext on disk        no shared keys
{{< /plate >}}

{{< plate-caption "The agent listens on no ports. The control plane never sees backup plaintext." >}}

<p style="max-width:42em;color:var(--mute);margin-top:22px;">On a schedule, it streams <code>pg_dump</code> through <code>zstd</code> compression and end-to-end encryption to your organisation&rsquo;s public key, then uploads the ciphertext directly to storage. Nothing of size touches local disk. The agent fetches a matching <code>pg_dump</code> binary for the server&rsquo;s major version on demand, from a signed registry. No shared system Postgres needed.</p>

{{< stub "Storage You Own" >}}

<p style="max-width:42em;color:var(--mute);">Backups go to a bucket you own and pay for, on any S3-compatible provider, or to your own SFTP destination. The control plane never holds the bytes.</p>

{{< plate-pair >}}
{{< plate title="Where the bytes live" num="Fig. 2" >}}
   your AWS account             bkpdb control plane
   ────────────────             ─────────────────────
   ┌─────────────┐              ┌──────────────────┐
   │   bucket    │              │   metadata DB    │
   │  ┌───────┐  │              │  ┌─────────────┐ │
   │  │ enc'd │  │              │  │ schedules   │ │
   │  │ 12 GB │  │              │  │ retention   │ │
   │  └───────┘  │              │  │ checksums   │ │
   │  ┌───────┐  │              │  │ audit log   │ │
   │  │ enc'd │  │              │  └─────────────┘ │
   │  │ 12 GB │  │              │                  │
   │  └───────┘  │              │   no bytes here  │
   └─────────────┘              └──────────────────┘
       ↑                                ↑
       └── ciphertext only ─────────────┘
{{< /plate >}}
{{< plate title="Providers" num="Fig. 3" dark="true" >}}
   ╔═══════════════════════════════╗
   ║  S3-compatible, all of them   ║
   ╚═══════════════════════════════╝

       ▣ AWS S3            ▣ Backblaze B2
       ▣ Cloudflare R2     ▣ Hetzner OS
       ▣ Wasabi            ▣ MinIO
       ▣ Scaleway          ▣ Tigris
       ▣ DigitalOcean      ▣ self-hosted
                              Ceph / RGW

   ─────────────────────────────────
   one config block, one set of
   credentials, one upload path.
{{< /plate >}}
{{< /plate-pair >}}

{{< stub "End-to-End Encryption" >}}

<p style="max-width:42em;color:var(--mute);">Each backup is encrypted on the host to your organisation&rsquo;s public key before it leaves the machine. The control plane never sees plaintext during a backup. The agent never holds a private key for any backup it has produced; a stolen agent cannot decrypt the archives it once made. The agent&rsquo;s own identity (its mTLS keypair) lives only on the host it was enrolled on. A compromised control plane cannot impersonate it.</p>

<p style="max-width:42em;color:var(--mute);margin-top:14px;">Credentials (database passwords, storage keys) are fetched per job, held in memory, never written to disk, and never written to the agent&rsquo;s logs. Connections in to the database use a least-privilege role you create. Storage destinations are validated end-to-end before they are saved (list, write, read, delete probe).</p>

{{< stub "Verified Restores" >}}

<p style="max-width:42em;color:var(--mute);"><em>On the roadmap, paid plans only.</em> Scheduled restores into a clean Postgres of the matching major version, on disposable infrastructure. Integrity checks run, your validation queries run, and the result (pass, fail, or alarm) is written to the audit log and surfaced on the database&rsquo;s detail page. This is the only case where the control plane decrypts a backup, and only because you asked it to.</p>

{{< plate title="The verifier loop, sketched" num="Fig. 4" >}}
   Mon 02:00   ┌─backup────┐                          [ OK ]
               │  pg_dump  ├──▶ encrypt ──▶ storage   ░░░░░
               └───────────┘                          ░░░░░
                                                      ░░░░░
   Mon 04:30   ┌─verify────┐  (roadmap, paid)         [ OK ]
               │  fetch    │                          ░░░░░
               │  decrypt  ├──▶ pg_restore ──▶ ✓      ░░░░░
               │  rowcount │                  fk ✓    ░░░░░
               │  your SQL │                  q  ✓    ░░░░░
               └───────────┘                          ░░░░░
                                                      ░░░░░
   audit log   verify.ok    db=orders  hash=0192a3..  ░░░░░
                                                      ░ X ░  ◀── one bar of red
   ─── 14-day record ──── ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  per failure, only
{{< /plate >}}

{{< plate-caption "Drawn here as a target. The plumbing exists in the agent; the schedulers and verifier infrastructure on the control plane are the work in front of us." >}}

{{< stub "Point-in-Time Recovery" >}}

<p style="max-width:42em;color:var(--mute);"><em>On the roadmap, after verified restores.</em> Continuous WAL streaming on top of the scheduled base backup, so the unit of recovery is a second instead of the last snapshot.</p>

<p style="max-width:42em;color:var(--mute);margin-top:14px;">The intended shape: the agent takes a periodic base backup of the cluster (the backup you already configure), and in parallel ships WAL segments to your storage as Postgres rolls them. A restore picks a base, replays WAL up to the timestamp or LSN you choose, and stops. Target RPO is measured in seconds, set by how aggressively WAL is shipped, not by your daily schedule.</p>

{{< plate title="Base + WAL, sketched" num="Fig. 5" >}}
   T0           ┌─ base backup ─┐
                │  pg_basebackup├──▶ encrypt ──▶ storage/base/...
                └───────────────┘

   T0 → T_now   ┌─ WAL shipping ─┐  (continuous)
                │  archive_command
                │  ─▶ encrypt    ├──▶ storage/wal/000000010000...
                │  ─▶ upload     │     000000010000...
                └────────────────┘     000000010000...
                                       ...

   recovery     pick base @ T_b, replay WAL until T_target, stop.
                target RPO ≈ ship interval (seconds).
{{< /plate >}}

{{< plate-caption "PITR is one continuous stream sat on top of the periodic backup. The agent already streams and encrypts; WAL shipping is the next channel through the same pipe." >}}

{{< stub "Restore From The Dashboard" >}}

<p style="max-width:42em;color:var(--mute);">Pick a backup in the dashboard, point it at a target connection, and the agent does the rest: fetch, decrypt, decompress, apply with <code>pg_restore</code>. The result is written to the audit log.</p>

{{< plate title="A restore, as the agent sees it" num="Fig. 5" >}}
  dispatched from dashboard
    snapshot  0192a3f4   2026-04-21  12.4 GB
    target    orders_staging  (Postgres 16.2, empty)

  ▸ fetching ............................. ok
  ▸ decrypting ........................... ok
  ▸ decompressing ........................ ok
  ▸ pg_restore --jobs=4 .................. ok

  ✓ restored to orders_staging in 4m 12s.
  ✓ audit:  restore.ok  actor=marcus@example.com
{{< /plate >}}

{{< stub "Retention & Audit" >}}

{{< plate-pair >}}
{{< plate title="GFS retention, drawn out" num="Fig. 6" >}}
   day  ▣▣▣▣▣▣▣ · · · · · · · · · · · · · · · · · ·
   wk   ▣ · · · · · · ▣ · · · · · · ▣ · · · · · · ▣
   mo   ▣ · · · · · · · · · · · · · · · · · · · · · ▣

        ── kept ──   ── pruned ──    ── kept ──

   default:  7 daily · 4 weekly · 12 monthly
   override per database, in the console.
{{< /plate >}}
{{< plate title="Audit log, sample" num="Fig. 7" >}}
   14:02:11   backup.start   db=orders
   14:04:38   backup.ok      db=orders  size=12.4G
   14:04:39   retain.delete  snap=0181…  reason=GFS
   04:31:02   verify.start   db=orders  ver=16
   04:33:48   verify.ok      db=orders  rows=ok fk=ok
   09:11:50   restore.start  by=marcus  to=staging
   09:16:02   restore.ok     elapsed=4m12s

   append-only · scoped per organisation
{{< /plate >}}
{{< /plate-pair >}}

{{< stub "The Trade-Offs" >}}

<p style="max-width:42em;color:var(--mute);">Every backup tool is a position on the same set of trade-offs. We take ours in writing.</p>

{{< ledger >}}
| Decision | What we do | What we give up |
|---|---|---|
| Logical vs. physical | Logical (`pg_dump`) in v1. PITR (base backup + continuous WAL) is next, after verified restores. | Sub-second RPO until PITR ships. |
| Where data lives | Your bucket or SFTP, your region. | The convenience of a one-click managed bucket. |
| Where keys live | Your organisation. The agent encrypts to the org public key and never holds the org private key. | Recovering from losing both your private key and your stored backups. |
| Verification | A roadmap feature, paid plans only. | A simpler product if we never ship it. |
| Audit | Everything consequential, append-only. | The freedom not to write some of it down. |
{{< /ledger >}}

{{< pullquote attrib="the working principle" >}}A backup that has not been restored is a wish, not a backup.{{< /pullquote >}}

