# ──────────────────────────────────────────────────────────────
# Pgvpd Configuration
# ──────────────────────────────────────────────────────────────
# Copy to pgvpd.conf and edit for your environment.
#
# All values shown are defaults. Uncomment and change as needed.
# Environment variables (PGVPD_*) and CLI flags override these.
# ──────────────────────────────────────────────────────────────
# ─── Listener ────────────────────────────────────────────────
# Port Pgvpd listens on for client connections
# port = 6432
# Address to bind to (use 0.0.0.0 to listen on all interfaces)
# listen_host = 127.0.0.1
# ─── Upstream PostgreSQL ─────────────────────────────────────
# Postgres host
# upstream_host = 127.0.0.1
# Postgres port (use your Supabase local port if applicable)
# upstream_port = 5432
# ─── Tenant Extraction ──────────────────────────────────────
# Character separating the role from the tenant payload in the username.
# With separator '.', username 'app_user.acme' yields:
# role = 'app_user', tenant = 'acme'
# tenant_separator = .
# Postgres session variable(s) set for each tenant connection.
# Your RLS policies should reference these via current_setting().
# Comma-separated for multiple variables.
# context_variables = app.current_tenant_id
# Separator for multiple values in the tenant payload.
# With context_variables = app.current_list_id,app.current_user_id
# and value_separator = :, username 'app_user.list123:user456' yields:
# app.current_list_id = 'list123'
# app.current_user_id = 'user456'
# value_separator = :
# ─── Role Override ──────────────────────────────────────────
# Override which role pgvpd switches to after authentication.
# By default, pgvpd does SET ROLE {rewritten_username}.
# Set this to use an existing NOLOGIN role (e.g., Supabase's
# "authenticated") so existing RLS policies work unchanged.
# Requires: GRANT <set_role> TO <login_role> on the database side.
# set_role = authenticated
# ─── Access Control ─────────────────────────────────────────
# Usernames that bypass tenant extraction entirely.
# These connections are passed through to upstream as-is.
# Comma-separated. Used for admin, migration, superuser access.
# superuser_bypass = postgres
# ─── TLS Termination (client → Pgvpd) ────────────────────
# Port for TLS-encrypted client connections.
# Requires tls_cert and tls_key. Plain listener stays on `port`.
# tls_port = 6433
# Path to PEM certificate file
# tls_cert = /etc/pgvpd/server.crt
# Path to PEM private key file
# tls_key = /etc/pgvpd/server.key
# ─── TLS Origination (Pgvpd → upstream Postgres) ────────
# Connect to upstream Postgres over TLS
# upstream_tls = false
# Verify upstream TLS certificate (set to false for self-signed)
# upstream_tls_verify = true
# Custom CA certificate for upstream verification
# upstream_tls_ca = /etc/pgvpd/upstream-ca.crt
# ─── Timeouts ────────────────────────────────────────────────
# Max seconds for startup + auth + injection handshake.
# Active queries (transparent pipe) are not affected.
# handshake_timeout = 30
# ─── Context Resolvers ───────────────────────────────────────
#
# Path to a TOML file defining context resolvers.
# Resolvers are SQL queries that run after authentication to derive
# additional session variables from database state (org memberships,
# team grants, ACLs). See resolvers.toml.example for format.
# resolvers = resolvers.toml
# ─── Connection Pooling ──────────────────────────────────────
#
# Session pooling reuses upstream connections across clients.
# In pool mode, pgvpd authenticates clients itself (cleartext)
# and connects to upstream using upstream_password.
#
# Superuser bypass connections are never pooled.
#
# Pool key: (database, role) — all tenants sharing a role/db
# reuse connections from the same bucket.
# Pool mode: none (default, passthrough) or session (pooling)
# pool_mode = none
# Max upstream connections per (database, role)
# pool_size = 20
# Password clients must provide when pool_mode = session.
# Required for session mode.
# pool_password = changeme
# Password pgvpd uses to authenticate to upstream Postgres.
# Required for session mode.
# upstream_password = changeme
# Seconds an idle pooled connection lives before being closed.
# pool_idle_timeout = 300
# Seconds to wait for a connection when the pool is full.
# pool_checkout_timeout = 5
# ─── Tenant Isolation ───────────────────────────────────────
#
# Per-tenant controls: allow/deny lists, connection limits, rate limits.
# These apply to the tenant payload extracted from the username.
# Only allow these tenants (comma-separated). All others rejected.
# Cannot be used with tenant_deny.
# tenant_allow = tenant_a, tenant_b
# Block these tenants (comma-separated). All others allowed.
# Cannot be used with tenant_allow.
# tenant_deny = blocked_tenant
# Max concurrent connections per tenant.
# tenant_max_connections = 50
# Max new connections per tenant per second.
# tenant_rate_limit = 100
# Seconds of inactivity before a tenant connection is terminated.
# In passthrough mode: connection lifetime timeout.
# In pool mode: idle timeout (resets on each data transfer).
# tenant_query_timeout = 300
# ─── Admin API ──────────────────────────────────────────────
#
# HTTP port for the admin API (health, metrics, pool status).
# Disabled by default. Enable for load balancer health checks
# and Prometheus metrics scraping.
# admin_port = 9090
# ─── Logging ─────────────────────────────────────────────────
# Log level: debug, info, warn, error
# log_level = info