Files
pawsql/README.md
Shaun Campbell 7d7133d6cc
All checks were successful
Build and Push Image / docker-build-and-push (push) Successful in 6m32s
Test and Release PawSQL / test (push) Successful in 50s
Test and Release PawSQL / release (push) Successful in 8s
feat: ship Barkstack UI plugin
2026-09-16 13:47:07 -04:00

5.9 KiB

PawSQL

PawSQL is a TLS-terminating PostgreSQL router. It accepts PostgreSQL clients on one address, chooses a configured route from the TLS Server Name Indication (SNI) or database name, and proxies the PostgreSQL stream to an external or PawSQL-managed PostgreSQL server.

Prerequisites

  • Go 1.24 or later to build and run PawSQL natively.
  • Docker Engine and a usable docker CLI to build the PawSQL image. PawSQL also needs them in its own execution environment when it manages PostgreSQL containers.
  • Optional: a TLS certificate and private key readable by PawSQL. Omit the tls block to serve plaintext PostgreSQL; with TLS, the certificate must cover every hostname clients use for SNI routing.
  • Docker Engine access for each postgres route. Managed database images are limited to postgres:16, postgres:17, and postgres:18.

Build, configure, and run

Build the independently owned Svelte plugin, then the native binary:

cd ui
bun install
bun run build
cd ..
go build -o pawsql ./cmd/pawsql

Create a Barkfile and validate it before starting:

./pawsql validate --config Barkfile
./pawsql --config Barkfile --admin-listen :9090

--config defaults to Barkfile. The PostgreSQL listener, TLS material, and at least one database route are required. --admin-listen defaults to :9090 and serves PawSQL's embedded Barkstack plugin at /barkstack/ui/; pass an empty value to disable it. The admin port is intended for Barkstack over localhost or a private overlay network, not direct publication.

To build and run the PawSQL container image for routes reachable from that container:

docker build -t pawsql .
docker run --rm --publish 5432:5432 \
  --volume "$PWD/Barkfile:/etc/pawsql/Barkfile:ro" \
  --volume "$PWD/tls:/etc/pawsql/tls:ro" \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  pawsql

The supplied image includes the compiled PawSQL Svelte plugin and Docker CLI; production does not run Node or Bun. The Docker CLI lets managed postgres routes create, start, and stop containers through the mounted Docker socket. The socket grants PawSQL root-equivalent control of the Docker host; mount it only for trusted Barkfiles and trusted administrators. Publish PostgreSQL port 5432 as needed, but leave admin port 9090 unpublished and let Barkstack proxy the UI.

Barkfile

A Barkfile has one pawsql block. Each database has a unique name and exactly one route type: an upstream external PostgreSQL address or a postgres managed database.

pawsql {
    listen :5432

    tls {
        cert /etc/pawsql/tls/fullchain.pem
        key /etc/pawsql/tls/privkey.pem
    }

    database reporting {
        hostname reports.db.example.com
        upstream reporting.internal:5432
    }

    database application {
        hostname app.db.example.com
        postgres {
            image postgres:17
            volume pawsql-application-data
            password_env APPLICATION_POSTGRES_PASSWORD
            idle_timeout 10m
            traffic_idle_timeout 1h
        }
    }
}

listen is PawSQL's TCP address. cert and key identify the client-facing TLS certificate and key. hostname is optional; it is used only for SNI routing. upstream is the address of an existing PostgreSQL server.

For a managed postgres route, image, volume, and password_env are required. On first use, PawSQL reads the named environment variable to create the database container and configures the database and PostgreSQL user with the route's database name. The named Docker volume preserves its data. Set the password environment variable in PawSQL's environment, not in the Barkfile.

See examples/Barkfile and its accompanying examples/docker-compose.yml for a two-route external PostgreSQL example with locally generated development certificates:

cd examples
docker compose up --build

Routing and TLS

When the Barkfile configures tls, PawSQL handles PostgreSQL's SSL negotiation and terminates client TLS before proxying PostgreSQL bytes to the selected upstream:

  • With SNI: PawSQL uses the TLS server name to select an exact configured hostname match. Hostname matching is case-insensitive and ignores a trailing dot. An unknown SNI name is rejected; PawSQL does not fall back to a database-name route when SNI is present.
  • Without SNI: After TLS is established, PawSQL reads the PostgreSQL startup message and selects the route whose database name exactly matches the requested PostgreSQL database. This makes a route without hostname usable by non-SNI clients.

Use a certificate trusted by clients and containing the SNI hostname they present. Clients that do not send SNI must request the configured database route name.

Without a tls block, PawSQL serves plaintext PostgreSQL: clients connect without SSL negotiation, and routes are selected only by database name. Hostname routing is unavailable because it relies on TLS SNI.

Managed PostgreSQL lifecycle

Managed PostgreSQL is lazy: PawSQL creates or starts its pawsql-<database> container only when a client selects that route, waits for PostgreSQL to accept connections, then proxies the session. PawSQL stops managed containers but does not remove their data volumes.

Two optional Go-duration controls govern stopping a managed container; 0 disables either control:

  • idle_timeout starts only after the last proxied client session closes. When that countdown expires, PawSQL stops the managed container.
  • traffic_idle_timeout starts for an open session and resets whenever PawSQL proxies bytes in either direction. When it expires, PawSQL stops the managed container even though sessions remain open.

traffic_idle_timeout is intentionally aggressive: it terminates open but silent sessions. Do not enable it for workloads that keep idle connections, transactions, listeners, or connection-pool sessions alive unless that interruption is acceptable.