Pouch vaults

A pouch-vault is a small daemon you run on a box you control — home server, NAS, Raspberry Pi, Mac mini, even your laptop. It connects to your pouch over a single outbound HTTPS link and mirrors every drop to a local SQLite archive as it happens. No public URL, no port forwarding, no firewall hole — works anywhere outbound HTTPS works.

The vault is open source (pointegrity/pouch-vault), a few thousand lines of Go, statically linked, no CGO. Pre-built binaries ship for Linux (amd64 / arm64), macOS (Intel / Apple Silicon) and Windows; a Docker image too.

How it fits (default: pull mode)

[pouch SaaS]  ◀──── outbound HTTPS SSE stream ────  [your vault]  ──▶  drops.db
              ◀──── outbound HTTPS heartbeat ─────
                  every 30 s: "I have N drops"

Both arrows go outward from your vault box. Pouch never tries to reach in. That's the property that makes this trivial to deploy on a laptop, behind CGNAT, on a corporate network, or anywhere else inbound connections aren't possible.

Drops arrive over a long-lived Server-Sent Events stream the vault holds open. Each event is HMAC-signed with the secret you minted at provisioning — wire format and verification semantics are the same as the webhook contract. Drops fired while the vault was offline are queued by pouch and replayed automatically when the vault reconnects.

1. Mint your vault (admin shell)

Today, vaults are admin-provisioned. From a shell on the pouch server:

pouch vault create --owner <your-user-id> --name <a-name-you-pick>

Output is shown once. Save these three values — you'll paste them into the vault's config:

POUCH_URL          https://pouch.pointegrity.com
POUCH_VAULT_KEY    pk_...                   # auth, long-lived
POUCH_HMAC_SECRET  ...                      # delivery signature
Self-service is on the roadmap. A "create vault" button in Settings → Replication is part of the next cut. Until then, ping support and we'll mint one for you.

2. Install

Pre-built binaries from the latest GitHub release:

# Apple Silicon
curl -fL -o pouch-vault https://github.com/pointegrity/pouch-vault/releases/latest/download/pouch-vault-darwin-arm64
chmod +x pouch-vault
sudo mv pouch-vault /usr/local/bin/

# Intel: replace darwin-arm64 with darwin-amd64.
curl -fL -o pouch-vault https://github.com/pointegrity/pouch-vault/releases/latest/download/pouch-vault-linux-amd64
chmod +x pouch-vault
sudo install -m 755 pouch-vault /usr/local/bin/

# arm64 (Pi, Graviton, ARM cloud): replace amd64 with arm64.
docker run -d --name pouch-vault \
  -p 7780:7780 \
  -v pouch-vault-data:/data \
  -e POUCH_URL=https://pouch.pointegrity.com \
  -e POUCH_VAULT_KEY=pk_... \
  -e POUCH_HMAC_SECRET=... \
  -e POUCH_PUBLIC_URL=https://vault.example/hook \
  ghcr.io/pointegrity/pouch-vault:latest

3. Run it

The vault is a foreground process that handles SIGTERM and logs to stderr. Pick whichever supervisor matches your OS:

Foreground (any OS)

POUCH_URL=https://pouch.pointegrity.com \
POUCH_VAULT_KEY=pk_... \
POUCH_HMAC_SECRET=... \
POUCH_PUBLIC_URL=https://vault.example/hook \
VAULT_DB=./drops.db \
pouch-vault

systemd (Linux servers, NAS, Pi)

Example unit at examples/pouch-vault.service. One EnvironmentFile= + systemctl enable --now and you're set.

launchd (always-on Mac)

Example plist at examples/com.pointegrity.pouch-vault.plist. Drop in ~/Library/LaunchAgents/ + launchctl load.

4. Verify it works

Drop something into your pouch (CLI, SPA, ingress key — whatever). Within a few seconds:

sqlite3 /var/lib/pouch-vault/drops.db \
  "SELECT received_at, drop_id, label
     FROM drops
    ORDER BY received_at DESC LIMIT 5"

You should see the drop you just made. Pair with litestream if you want the vault's database continuously replicated to S3 / B2 for offsite backup at minute-level RPO.

Producer mode (watch paths)

A vault isn't only a mirror — it can also originate drops by watching local folders. Point a path at a stream with direction: "watch" and the vault computes a sha256 per file, debounces edits, and uploads new or changed files as drops on the named stream.

VAULT_PATHS='[{"path":"~/scrape-out","stream":"scrape","direction":"watch"}]'

Companion CLI subcommands: pouch-vault sync (one-shot reconcile), pouch-vault history, pouch-vault get <id>. See the project README for the full VAULT_PATHS schema and per-direction behavior.

Advanced: push mode

If you actually want pouch to POST to a publicly-reachable URL you operate (a server with a static IP and a real domain, a cloudflared tunnel terminating at your laptop, an nginx in front of a NAS) you can use push mode. Set POUCH_PUBLIC_URL in your config to the URL pouch should POST to, and the vault exposes /hook instead of opening an outbound stream.

Push and pull are per-vault. Same binary, same provisioning flow — the vault switches based on whether POUCH_PUBLIC_URL is set. You can run multiple vaults and have some pull, some push, depending on what each box looks like.

tunnel pattern (push mode)good for
cloudflared tunnelNAT-friendly, free tier covers personal use
tailscale funnelif Tailscale is already in your stack
nginx + Let's Encryptfull control on a server you operate

Most users should use the default pull mode. Push mode exists for a small set of advanced operators with pre-existing public infrastructure. Either works equally well from the SaaS side; the bytes go through HMAC + HTTPS regardless.

FAQ

Does the vault see my drop bodies in plaintext?

Yes — today, drop bodies are plaintext on the wire. The HMAC protects integrity (nobody can forge a delivery), not confidentiality. Sealed drops (end-to-end encryption) are a separate roadmap item; when they ship, vaults will store opaque ciphertext alongside the metadata.

What happens if my vault is offline when a drop arrives?

In the default pull mode, nothing is lost. Drops fired while the vault was disconnected are queued by pouch and replayed automatically over the SSE stream when the vault reconnects — no manual action, no re-deliver step.

In push mode, pouch retries the HTTP POST with geometric backoff at 30 s / 2 m / 8 m, four attempts total. After that the delivery is marked failed in pouch's outbox and sits there for manual re-delivery.

Can I run multiple vaults?

Yes. Each gets its own pouch vault create, its own key, its own database. Run one on your home server and one on a VPS for redundancy — pouch will deliver to both. The replication-status panel will show both side-by-side.