Docker Setup Docs

All WoWSQL services are published as pre-built Docker images on Docker Hub. Pull them directly, add your configuration, and run. No Git required.

Alternative: If you prefer to clone the full repo with all config files ready, see Setup with Git.

Official Docker Images

We publish 6 images under the wowsql namespace on Docker Hub:

ImageDescriptionPull Command
wowsql/postgres PostgreSQL 18 with pgvector, pg_cron, pgjwt & more docker pull wowsql/postgres:18
wowsql/auth Authentication (signup, login, JWT, OAuth) docker pull wowsql/auth:latest
wowsql/storage File storage with bucket-based access docker pull wowsql/storage:latest
wowsql/realtime WebSocket database change notifications docker pull wowsql/realtime:latest
wowsql/backend Dashboard API (admin auth, settings, DB ops) docker pull wowsql/backend:latest
wowsql/studio Web dashboard UI (Next.js) docker pull wowsql/studio:latest

Pull all images at once

docker pull wowsql/postgres:18
docker pull wowsql/auth:latest
docker pull wowsql/storage:latest
docker pull wowsql/realtime:latest
docker pull wowsql/backend:latest
docker pull wowsql/studio:latest

Additionally, we use two community images (not published by us):

  • postgrest/postgrest:v12.2.0 — auto-generated REST API from your schema
  • kong:3.9 — API gateway for routing
  • redis:7-alpine — caching and pub/sub

Prerequisites

  • Docker Engine 20.10 or later
  • Docker Compose v2.0 or later (included with Docker Desktop)
  • At least 2 GB RAM available for containers
  • Ports 8080, 5432, and 3000 available on the host

Setup Steps

Create a project directory

mkdir wowsql && cd wowsql

Create the environment file

Create a .env file — this is the only config you need to customize:

# .env

# REQUIRED — change these
POSTGRES_PASSWORD=your-strong-password-here
JWT_SECRET=your-jwt-secret-at-least-32-characters-long

# OPTIONAL — defaults shown
POSTGRES_USER=postgres
POSTGRES_DB=postgres
POSTGRES_PORT=5432
API_PORT=8080
STUDIO_PORT=3000
API_EXTERNAL_URL=http://localhost:8080
STUDIO_EXTERNAL_URL=http://localhost:3000
Important: The JWT_SECRET is used to generate your API keys (anon and service_role). Keep it private. If you change it later, all existing keys are invalidated.

Create docker-compose.yml

This file tells Docker how to run all WoWSQL images together:

services:
  db:
    image: wowsql/postgres:18
    restart: unless-stopped
    ports:
      - "${POSTGRES_PORT:-5432}:5432"
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB:-postgres}
      JWT_SECRET: ${JWT_SECRET}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 10

  rest:
    image: postgrest/postgrest:v12.2.0
    restart: unless-stopped
    depends_on:
      db: { condition: service_healthy }
    environment:
      PGRST_DB_URI: postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-postgres}
      PGRST_DB_SCHEMAS: public,storage
      PGRST_DB_ANON_ROLE: anon
      PGRST_JWT_SECRET: ${JWT_SECRET}

  auth:
    image: wowsql/auth:latest
    restart: unless-stopped
    depends_on:
      db: { condition: service_healthy }
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-postgres}
      JWT_SECRET: ${JWT_SECRET}
      API_EXTERNAL_URL: ${API_EXTERNAL_URL:-http://localhost:8080}

  storage:
    image: wowsql/storage:latest
    restart: unless-stopped
    depends_on:
      db: { condition: service_healthy }
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-postgres}
      JWT_SECRET: ${JWT_SECRET}
    volumes:
      - storage-data:/var/lib/storage

  realtime:
    image: wowsql/realtime:latest
    restart: unless-stopped
    depends_on:
      db: { condition: service_healthy }
      redis: { condition: service_started }
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-postgres}
      JWT_SECRET: ${JWT_SECRET}
      REDIS_URL: redis://redis:6379

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis-data:/data

  kong:
    image: kong:3.9
    restart: unless-stopped
    ports:
      - "${API_PORT:-8080}:8000"
    environment:
      KONG_DATABASE: "off"
      KONG_DECLARATIVE_CONFIG: /kong/kong.yml
      KONG_DNS_ORDER: LAST,A,SRV,CNAME
      KONG_PLUGINS: bundled,cors,key-auth,request-transformer
    volumes:
      - ./kong.yml:/kong/kong.yml:ro
    depends_on: [rest, auth, storage, realtime, backend]

  backend:
    image: wowsql/backend:latest
    restart: unless-stopped
    depends_on:
      db: { condition: service_healthy }
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-postgres}
      JWT_SECRET: ${JWT_SECRET}
      API_EXTERNAL_URL: ${API_EXTERNAL_URL:-http://localhost:8080}

  studio:
    image: wowsql/studio:latest
    restart: unless-stopped
    ports:
      - "${STUDIO_PORT:-3000}:3000"
    environment:
      NEXT_PUBLIC_API_URL: ${API_EXTERNAL_URL:-http://localhost:8080}
    depends_on: [kong]

volumes:
  db-data:
  storage-data:
  redis-data:

Create Kong gateway config

Create kong.yml — this routes API requests to the correct service:

_format_version: "3.0"

services:
  - name: rest
    url: http://rest:3000
    routes:
      - name: rest-route
        paths: ["/rest/v1"]
        strip_path: true

  - name: auth
    url: http://auth:9999
    routes:
      - name: auth-route
        paths: ["/auth/v1"]
        strip_path: true

  - name: storage
    url: http://storage:5000
    routes:
      - name: storage-route
        paths: ["/storage/v1"]
        strip_path: true

  - name: realtime
    url: http://realtime:4000
    routes:
      - name: realtime-route
        paths: ["/realtime/v1"]
        strip_path: true

  - name: backend
    url: http://backend:8000
    routes:
      - name: backend-route
        paths: ["/api/v1"]
        strip_path: true

plugins:
  - name: cors
    config:
      origins: ["*"]
      methods: [GET, POST, PUT, PATCH, DELETE, OPTIONS]
      headers: [Content-Type, Authorization, apikey, X-Client-Info]
      exposed_headers: [Content-Range]
      credentials: true

  - name: request-transformer
    config:
      add:
        headers: ["X-Forwarded-Proto:https"]

Run it

docker compose up -d

Docker pulls all images from Docker Hub and starts the stack. First run takes 1-2 minutes.

Verify everything is up

docker compose ps

All services should show running or healthy within 30 seconds.

Open the dashboard

Visit http://localhost:3000 — create your admin account on first launch.

Done! Your WoWSQL instance is running. API keys are available in the dashboard under Settings.

Your File Structure

That's it — just 3 files:

wowsql/
├── .env               # your secrets & config
├── docker-compose.yml # service definitions
└── kong.yml           # API gateway routing

Configuration Reference

VariableRequiredDefaultDescription
POSTGRES_PASSWORDYesPostgreSQL superuser password
JWT_SECRETYesSecret for signing JWTs (min 32 chars)
POSTGRES_USERNopostgresPostgreSQL username
POSTGRES_DBNopostgresDefault database name
POSTGRES_PORTNo5432Host port for PostgreSQL
API_PORTNo8080Host port for API gateway
STUDIO_PORTNo3000Host port for dashboard
API_EXTERNAL_URLNohttp://localhost:8080Public URL for API (set if behind reverse proxy)
STUDIO_EXTERNAL_URLNohttp://localhost:3000Public URL for dashboard

Image-Specific Configuration

Each WoWSQL image accepts these environment variables:

wowsql/postgres:18

VariableDescription
POSTGRES_PASSWORDSuperuser password (required)
POSTGRES_USERSuperuser name (default: postgres)
POSTGRES_DBDefault database (default: postgres)
JWT_SECRETUsed by init scripts to configure pgjwt

Pre-installed extensions: pgvector, pg_cron, pgjwt, pgaudit, http, pg_hint_plan, hypopg, pg_repack, pg_partman, rum, pgtap, plpgsql_check.

wowsql/auth:latest

VariableDescription
DATABASE_URLPostgreSQL connection string
JWT_SECRETSecret for signing auth tokens
API_EXTERNAL_URLPublic API URL (for OAuth redirect)

wowsql/storage:latest

VariableDescription
DATABASE_URLPostgreSQL connection string
JWT_SECRETSecret for verifying access tokens

Mount a volume to /var/lib/storage for persistent file storage.

wowsql/realtime:latest

VariableDescription
DATABASE_URLPostgreSQL connection string
JWT_SECRETSecret for verifying WebSocket tokens
REDIS_URLRedis connection for pub/sub

wowsql/backend:latest

VariableDescription
DATABASE_URLPostgreSQL connection string
JWT_SECRETSecret for admin token signing
API_EXTERNAL_URLPublic API URL

wowsql/studio:latest

VariableDescription
NEXT_PUBLIC_API_URLAPI gateway URL (where the browser calls)

Updating Images

Pull the latest versions and restart:

docker compose pull
docker compose up -d

Or update a specific service:

docker pull wowsql/backend:latest
docker compose up -d backend

Management

Stop all services

docker compose down

Stop and delete all data

docker compose down -v
Caution: -v removes all database data, uploaded files, and Redis data permanently.

View logs

docker compose logs -f
docker compose logs -f auth

Restart a service

docker compose restart backend

Troubleshooting

Image pull fails

Make sure you can reach Docker Hub:

docker pull hello-world

If behind a corporate proxy, configure Docker daemon proxy settings.

Services not starting

docker compose ps
docker compose logs [service-name]

Database not ready

PostgreSQL takes a few seconds to initialize on first run:

docker compose logs db | grep "ready to accept connections"

API returns 401

Pass the correct API key in both apikey and Authorization: Bearer headers. Get keys from dashboard Settings.

Next: Connect your app using the SDK guide, or explore the architecture overview.