How to reach an app's database — wbsp db

The platform's database (AWS RDS) lives inside the VPC with no public endpoint — that's correct for security, but it means your laptop can't connect to it directly, and kubectl port-forward only forwards to Pods (RDS isn't a Pod).

wbsp db solves this with one command. It tunnels to the database through a small, internal-only relay that the platform runs in the cluster, and it figures out the connection details for you — so you can run migrations, open psql, or point a GUI client at the database without any manual setup.

Quick reference lives in Useful commands; this page is the full how-to. (A manual fallback using the admin user and a throwaway in-cluster pod exists for operators, but needs direct cluster access.)


How it works

your laptop ──kubectl port-forward──▶ wbsp-db-proxy relay ──▶ private RDS
            (over the Kubernetes API)   (in the cluster)     (in the VPC)
  • The relay (wbsp-db-proxy in the wbsp-system namespace) is a tiny TCP forwarder. It's provisioned with the platform, not per app, and one relay serves every app's database — the database is chosen by your connection, not by the relay.
  • wbsp db opens a kubectl port-forward to that relay on a free local port, reads the app's database connection (host/port/name/user/password) from the deployed app's pod, and points your command/psql/GUI at localhost.
  • PostgreSQL TLS is negotiated end to end (your client ↔ RDS). The relay only forwards bytes, so encryption works through it. The connection uses sslmode=require (encrypt without verifying the CA — the RDS CA isn't in your local trust store and the traffic is inside the VPC).

The relay is transport only: it does not bypass database authentication. You still need the app's database credentials to connect — which wbsp db reads for you from the app you have access to.


Prerequisites

  • The app must be deployed. wbsp db reads the connection from the running app's pod env, so deploy the app first (wbsp deploy --config wbsp.yaml --destination prod). If it isn't deployed, the command tells you so.
  • Your kubectl must point at the cluster (the tunnel rides the Kubernetes API, so this also enforces access control). Your platform operator gives you the cluster name and region, and an access entry for the cluster. Then:
    aws eks update-kubeconfig --name <cluster> --region <region>
  • For db connect only: a local psql. On macOS, brew install libpq installs it, but libpq is keg-only, so add it to your PATH:
    echo 'export PATH="$(brew --prefix libpq)/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
    On Debian/Ubuntu: apt-get install postgresql-client. The other verbs (run, proxy, url) don't need psql.

The commands

Run these from the app's directory (where its wbsp.yaml is). An aws destination is the remote database; a local-machine destination (compose/dev/standalone) talks to the docker-compose database directly with no relay. Below, prod names an aws destination and compose names a local-machine one.

db run — run a command with the database in its env (migrations)

The headline use case. Opens a tunnel, sets the standard DATABASE_* / DATABASE_URL environment to point at localhost, runs your command, then tears the tunnel down — and propagates the command's exit code.

# Apply Prisma migrations against the app's real database
wbsp db run --config wbsp.yaml --destination prod -- npx prisma migrate deploy

# Seed script, or anything that reads DATABASE_URL / DATABASE_*
wbsp db run --config wbsp.yaml --destination prod -- node scripts/seed.js

Everything after -- is your command, run verbatim.

db connect — interactive psql

Opens a tunnel and drops you into a psql session against the app's database.

wbsp db connect --config wbsp.yaml --destination prod

The connection is supplied to psql via libpq PG* environment variables, so no flags are needed. Exit psql (\q) and the tunnel closes automatically.

db proxy — hold a tunnel open for a GUI client

Opens a tunnel on a local port, prints the connection details (including the password, so you can paste them into TablePlus / DBeaver / pgAdmin), and holds open until you press Ctrl-C.

wbsp db proxy --config wbsp.yaml --destination prod
# Database tunnel open. Connect with:
#   host=localhost
#   port=54981
#   dbname=test_wbsp_website
#   user=test_wbsp_website_user
#   password=••••••••
#   url=postgresql://...@localhost:54981/test_wbsp_website?sslmode=require
# Holding open — press Ctrl-C to close.

# Pin a specific local port instead of auto-picking a free one:
wbsp db proxy --config wbsp.yaml --destination prod --port 6543

db proxy is the only command that prints the password — by design, so you can configure a GUI. The others never print it.

db url — print the connection string

wbsp db url --config wbsp.yaml --destination prod

For a local-machine destination this string is directly usable; for an aws destination it's relative to an open tunnel (use db proxy to get the live localhost:PORT form).


Local vs AWS

destination typeWhat wbsp db does
compose / dev / standaloneConnects directly to the docker-compose Postgres — no relay.
aws (incl. mode: demo)Tunnels through the wbsp-db-proxy relay to private RDS.

If your wbsp.yaml defines only one destination, you can omit --destination; with more than one, pass it explicitly.


Security & access

  • The relay is internal-only (a ClusterIP Service — never a LoadBalancer or NodePort) and locked down by a NetworkPolicy: it may egress only to the database, and it accepts no in-cluster traffic. The only way to reach it is kubectl port-forward, which goes through the Kubernetes API server — so reaching the database requires valid cluster credentials + RBAC.
  • The relay does not bypass database authentication. You connect with the app's own database user; the relay just moves bytes.
  • The password is passed to wrapped tools and psql via environment only — never as a CLI flag, never logged, never written to disk. Only db proxy prints it, and only because you asked it to.

Operator: the relay

The relay is part of the platform, not something developers create. wbsp-platform up builds it (a Deployment, a ClusterIP Service and a NetworkPolicy named wbsp-db-proxy, in the wbsp-system namespace). To check it is there:

kubectl -n wbsp-system get deploy,svc,netpol -l app=wbsp-db-proxy

If the relay is missing, wbsp db --destination prod (an aws destination) fails with a clear message asking the operator to rebuild the platform.


Troubleshooting

SymptomCause / fix
deploy the app firstThe app isn't running (no pod to read the connection from). wbsp deploy it, then retry.
psql not found on PATHInstall the client; on macOS add keg-only libpq to PATH (see Prerequisites).
relay-missing / "provision the platform" errorThe wbsp-db-proxy relay isn't deployed — an operator runs wbsp-platform up for the platform.
invalid sslmode value from a custom clientUse libpq's sslmode=require (what wbsp db emits). no-verify is a node-postgres-only value; node apps build their URL from the DATABASE_* parts instead.
Connection refused on localhost:PORT after db proxyThe tunnel closed (you pressed Ctrl-C or it errored). Re-run db proxy; check kubectl still has cluster access.

See also