Repository navigation
v0.19.0 — relay on Postgres, direct serve mode
Promoted from v0.19.0-rc.1 as a same-commit re-tag: identical binaries, now validated in production — the hosted relay at public.getpiper.dev has been running this build on Postgres since 2026-09-03, with its data carried over by the copier (~2 s of downtime, every agent re-registered with its existing token).
The headline change is infrastructure: piper-relay stores its state in Postgres instead of a SQLite file.
Manual upgrade steps — read before upgrading
Relay operators (hosted or self-hosted)
- Provision Postgres and set
PIPER_RELAY_DB_URL. The relay refuses to start without it (PIPER_RELAY_DB_URL is required (postgres://user:password@host/dbname)). Tables are created on first start.PIPER_RELAY_DATA_DIRremains the mount point for the TLS pair and the GitHub App key;relay.dbis no longer read or written. Full procedure:docs/runbooks/relay-deploy.md→ 2. Configure. - Existing data: copy it with the one-off
cmd/relay-sqlite-to-pg(go run ./cmd/relay-sqlite-to-pg -sqlite relay.db -pg "$PIPER_RELAY_DB_URL") before starting the new binary — tokens, accounts, GitHub App links, custom domains, and repo bindings survive; no re-enrollment. The copier is temporary and is removed after the hosted cutover (#516). Or start empty and let boxes re-login. Running relay and Postgres together on one public-IP host? The runbook's Single host with compose section is the exact procedure used for the hosted relay's cutover, including the host-networking, certbot-mount, and nightly-dump details. - systemd: the shipped
piper-relay.servicenow carriesAfter=postgresql.serviceandStartLimitIntervalSec=0, so a relay that boots before its database keeps retrying instead of tripping systemd's start-rate limit. Install the new unit file, not just the binary. - Relay before agents, as always. The agent↔relay wire protocol is unchanged, so boxes on v0.18.0 keep working against a v0.19.0 relay.
Agent (piperd) operators
domain_config gained a serve column (direct-serve mode, #508). Schema is applied with CREATE TABLE IF NOT EXISTS, so an existing piper.db does not pick it up on its own. Either apply it in place before restarting —
sqlite3 /var/lib/piper/piper.db "ALTER TABLE domain_config ADD COLUMN serve TEXT NOT NULL DEFAULT 'relay';"— or start with a fresh DB and redeploy. Boxes without a custom domain configured are unaffected either way.
What's new
- Relay on Postgres (#515, #517): one shared database for every relay process; SQLite removed from the relay. SQLite's global write lock is replaced by row-level locking on the enroll/app/domain cap checks and on the parked-webhook drain, each covered by a concurrency test against real Postgres. Foreign keys are now enforced. Fixes a latent tie-break in org-target GitHub App install routing that would have picked the wrong org under Postgres NULL ordering.
- Direct serve mode (#505/#508, #506/#511): a box-wide custom domain can be served by the box's own
:443(DNS → box), with the relay kept for login, webhooks, and control; per-app custom domains get DNS-01 certs through the same token source, no relay splice. - Direct HTTPS on a never-enrolled box (#509).
- PROXY protocol v2 on the relay's public listeners, opt-in via
PIPER_RELAY_PROXY_PROTOCOL=1(#485/#500), so rate limiting and logs key on the real client IP behind a trusted L4 proxy. - TUI: list and switch to relay boxes (#504).
- Relay logs failed terminate-path TLS handshakes, rate-gated (#501). Token and installation listings order by insertion, not lexical RFC3339Nano (#503). Tilde-free asset names for prerelease debs (#502). Repo hygiene: issue forms, PR template, SECURITY.md, CONTRIBUTING.md (#512, #514).
Still one replica
Postgres removes the database as a reason the relay can't scale out, but two per-process states remain — tunnel sessions and in-flight login flows — so run exactly one relay until those follow-ups land. The runbook's container section spells this out.
Known issues shipped open
PIPER_RELAY_DATA_DIRis created but no longer read by the relay itself (certs and the App key are addressed by their own env vars); it stays as the documented mount point for now.cmd/relay-sqlite-to-pgships in this release and will be deleted once the hosted relay has moved (#516).