sota.io

Managed PostgreSQL

Provision a managed PostgreSQL database for your application with zero configuration.

Overview

sota.io can provision a dedicated PostgreSQL 17 instance for each project. The database includes automatic connection pooling via PgBouncer, daily backups with 7-day retention, and auto-injected credentials.

Provisioning

Auto-Provisioning

Databases are auto-provisioned on your first deploy. The deploy engine calls ensureDatabase automatically, so you do not need to provision manually. The DATABASE_URL will be injected into your app container before it starts.

Via API

If you want to provision a database before your first deployment, you can use the API explicitly:

curl -X POST https://api.sota.io/v1/projects/550e8400-.../database \
  -H "Authorization: Bearer <token>"

That is it. No configuration needed.

What Happens

  1. A PostgreSQL 17 container is created (sota-db-{slug})
  2. A PgBouncer sidecar is started for connection pooling (sota-pgbouncer-{slug})
  3. A cryptographically random password is generated
  4. DATABASE_URL is automatically injected into your app container

Connecting

The DATABASE_URL environment variable is available in your application without any manual configuration:

// Node.js with pg
const { Pool } = require('pg');
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
# Python with psycopg2
import os
import psycopg2

conn = psycopg2.connect(os.environ["DATABASE_URL"])

DATABASE_URL Format

The DATABASE_URL injected into your app follows this format:

postgresql://app_{slug}:{password}@sota-pgbouncer-{slug}:5432/{slug}?sslmode=disable
ComponentValueExample
Userapp_{slug}app_my-app
Password32 hex chars (auto-generated)a1b2c3...
Hostsota-pgbouncer-{slug}sota-pgbouncer-my-app
Port54325432
Database{slug}my-app
SSL ModedisableSee Security

The connection URL points to PgBouncer (port 5432), not directly to PostgreSQL. This provides automatic connection pooling.

Connection Pooling

Every database includes PgBouncer for connection pooling:

SettingValue
Pool ModeTransaction
Default Pool Size20
Max Client Connections100

This means your application can open up to 100 connections, and PgBouncer will multiplex them over 20 actual PostgreSQL connections.

Backups

Databases are automatically backed up daily:

FeatureDetail
Methodpg_dump via Docker exec
Compressiongzip
ScheduleEvery 24 hours
Retention7 days
StorageServer local disk

List Backups

curl https://api.sota.io/v1/projects/550e8400-.../database/backups \
  -H "Authorization: Bearer <token>"

Trigger Manual Backup

curl -X POST https://api.sota.io/v1/projects/550e8400-.../database/backups \
  -H "Authorization: Bearer <token>"

Creates an on-demand backup in addition to the automatic daily backups.

Security

  • Database containers run on runc (not gVisor) as trusted system services
  • Passwords are generated using crypto/rand (32 hex characters)
  • The DATABASE_URL is encrypted at rest using the same AES-256-GCM encryption as other environment variables
  • Network access is restricted to containers on the same Docker network

Why sslmode=disable?

The DATABASE_URL uses sslmode=disable. This is safe because of the network architecture:

  • All containers (your app, PgBouncer, PostgreSQL) run on the same Docker bridge network (traefik-public) on the same physical host
  • Traffic between containers never leaves the machine or traverses any external network
  • There is no network path where an attacker could intercept the connection
  • PgBouncer uses AUTH_TYPE=plain for the same reason -- all communication is internal-only

Despite SSL being disabled for the internal connection, credentials are still protected:

  • Passwords are cryptographically strong (32 hex characters generated via crypto/rand)
  • The DATABASE_URL environment variable is encrypted at rest using AES-256-GCM
  • Database passwords are never exposed via the API