PgBeam
PgBeam Docs

Self-hosted data plane (BYOC)

Run the PgBeam proxy inside your own VPC or cluster so the agent connection and audit stream never leave your network, while the control plane, policy engine, and dashboard stay hosted by PgBeam.

The self-hosted (BYOC, "bring your own cloud") data plane runs the same PgBeam proxy image inside your own network. Queries from your agents flow through a proxy you operate; the proxy only dials home to the PgBeam control plane over gRPC to fetch project config and to ship the audit trail back. Your database credentials and query traffic stay in your VPC.

This is a Scale and enterprise capability. It sells the compliance story: your data plane, our policy engine.

What stays where

ComponentRuns where
Proxy (PG wire, policy, cache)Your VPC/cluster
Query traffic + DB credentialsYour VPC/cluster
Control plane (config, billing)PgBeam (hosted)
Dashboard, policy authoringPgBeam (hosted)
Audit trailShipped to PgBeam over gRPC

The proxy enforces every policy (read-only, allowlists, masking, budgets, approvals, kill-switch) locally in the PG wire protocol. It receives that policy from the control plane over the config stream, the same mechanism the hosted data plane uses.

How enrollment works

A self-hosted proxy authenticates to the control plane with a self-host enrollment token. The token:

  • Is issued once per enrollment and shown a single time. Only its SHA-256 hash is stored.
  • Scopes the proxy to your organization. A self-hosted proxy receives config for your projects only, never another tenant's, and never the PgBeam platform TLS key.
  • Is gated on entitlement. If your organization is not on a self-host-capable plan (Scale or enterprise), the connection is rejected.
  • Can expire, be rotated, and be revoked. All three take effect immediately, including for proxies that are already connected. See the token lifecycle below.

Because the proxy runs in your network, you provide its TLS certificate for your proxy domain. The platform wildcard certificate is never streamed to a self-hosted proxy.

Issue an enrollment token

Create an enrollment for your organization (owner or admin):

curl -X POST https://api.pgbeam.com/v1/organizations/$ORG_ID/self-host-enrollments \
  -H "Authorization: Bearer $PGBEAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"region_label": "customer-vpc-us-east", "description": "prod cluster", "expires_at": "2027-01-01T00:00:00Z"}'

expires_at is optional; omit it for a token that never expires. Setting it gives the token a hard TTL, which keeps the blast radius of a leak small.

The response includes the plaintext token once:

{
  "enrollment": {
    "id": "she_...",
    "org_id": "org_...",
    "region_label": "customer-vpc-us-east"
  },
  "token": "pbh_..."
}

Store the token securely; it cannot be retrieved again. List enrollments with GET on the same path.

Token lifecycle

Treat an enrollment token like any other production secret, and use expiry and rotation to limit how long a leaked token stays useful.

  • Expiry: an expired token is rejected fail-closed at the control plane's gRPC auth gate the instant its expires_at passes. Expiry is visible in the list endpoint and the dashboard.
  • Rotation: POST /v1/organizations/{org_id}/self-host-enrollments/{enrollment_id}/rotate mints a new token for the same enrollment (same id, metadata, and expiry) and returns it once. The swap is atomic: the old token stops authenticating new connections the moment the call returns. Update the proxy's secret (controlPlane.enrollmentToken in Helm, PGBEAM_ENROLLMENT_TOKEN in compose) and restart or roll the proxy to pick up the new token.
  • Revocation: DELETE .../self-host-enrollments/{enrollment_id} cuts the enrollment off permanently. Revoked enrollments cannot be rotated; issue a new enrollment instead.

Expiry, rotation, and revocation stop new gRPC connections and also terminate the streams a connected proxy already holds. On revoke or rotate, the control plane closes the proxy's live streams the moment the change commits; a stream opened before an expiry instant is closed when that instant passes. The proxy sees a permission_denied status naming the enrollment and the reason in its logs, then reconnects with backoff and fails auth until it presents a currently valid token. Rotate first, roll the proxy with the new token, and the old token is dead from the moment of rotation; there is no shared-secret overlap window to manage.

Mark a project self-hosted

Set self_hosted when creating a project so the control plane treats its data plane as customer-operated and does not provision hosted infrastructure for it:

curl -X POST https://api.pgbeam.com/v1/projects \
  -H "Authorization: Bearer $PGBEAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-app", "org_id": "org_...", "self_hosted": true, "database": { "host": "db.internal", "name": "app", "username": "app" }}'

Run the proxy

Packaging for both Kubernetes and Docker Compose lives in deploy/byoc/.

Helm

helm install pgbeam-proxy ./deploy/byoc/helm/pgbeam-proxy \
  --set controlPlane.url=https://grpc.pgbeam.com \
  --set controlPlane.enrollmentToken=pbh_... \
  --set proxy.domain=proxy.internal.example.com \
  --set-file tls.cert=./tls.crt \
  --set-file tls.key=./tls.key

Docker Compose

cd deploy/byoc
cp .env.example .env      # fill in PGBEAM_CONTROL_PLANE_URL and PGBEAM_ENROLLMENT_TOKEN
docker compose up -d

Connect your agents

Route clients through the proxy using TLS SNI, exactly as with the hosted data plane, but against your proxy domain:

postgresql://user:pass@<project-subdomain>.proxy.internal.example.com:5432/db?sslmode=verify-full

The subdomain identifies the project. The proxy resolves it against the config streamed from the control plane.

Configuration reference

The proxy is configured entirely with environment variables. The most relevant for BYOC:

VariablePurpose
AGENT_API_URLControl-plane gRPC URL to dial home to
GRPC_AUTH_TOKENSelf-host enrollment token (pbh_...)
AGENT_REGIONRegion label reported to the control plane
AGENT_INSTANCEUnique instance id for this proxy
PROXY_DOMAINBase domain for TLS SNI project routing
TLS_CERT_FILEPath to your proxy TLS certificate
TLS_KEY_FILEPath to your proxy TLS private key
SERVERLESS_ADDRListen address for the Neon-compatible HTTP/WS + MCP endpoint
CACHE_ENABLEDEnable query caching (off by default)

Limits and follow-ups

  • Config, audit, and hostname self-heal are scoped to the enrolling org. Metrics and insights reporting from a self-hosted proxy are trusted at the org level; fine-grained per-project scoping of those aggregate reports is a planned follow-up.

On this page