Self-hosting

Straden is deployed with Docker Compose from a single image, ghcr.io/kwasii1/straden. Every setting is optional — the defaults give you a working local instance.


Quick start (local)

BASH
mkdir straden && cd straden
curl -fsSLO https://raw.githubusercontent.com/kwasii1/straden/main/deploy/compose.yaml
curl -fsSL https://raw.githubusercontent.com/kwasii1/straden/main/deploy/.env.example -o .env
docker compose up -d

Open http://localhost:8000 and create the admin account in the setup wizard.

Services

ServiceWhat it does
appWeb UI + MCP server (FrankenPHP/Caddy). Proxies websockets to Reverb and handles HTTPS. Runs database migrations on start.
reverbWebsocket server for live run progress, chat streaming and notifications.
runnerQueue worker (Horizon) that executes k6 load tests. Ships with k6 v2.0.0.
schedulerChecks running tests and finalises them.
postgresApplication database.
redisCache, sessions and queues.
influxdbInfluxDB 1.8 — k6 time-series metrics.

The reverb, runner and scheduler services wait for app to become healthy, so secrets and migrations are always in place before they start.

Running on a VPS with HTTPS

  1. Point a DNS record (e.g. straden.example.com) at the server.

  2. In .env:

    DOTENV
    STRADEN_DOMAIN=straden.example.com
    APP_URL=https://straden.example.com
    HTTP_PORT=80
    HTTPS_PORT=443
    DB_PASSWORD=change-me-before-first-start
    
  3. docker compose up -d

Caddy obtains and renews the Let's Encrypt certificate automatically. Websockets use the same origin (wss://straden.example.com/app/...), so there is no extra port to open.

Behind your own reverse proxy

If nginx, Traefik or a load balancer already terminates TLS, keep STRADEN_DOMAIN=:80, set APP_URL to the public HTTPS URL, and proxy everything — including websocket upgrades on /app/* — to the app container's port 80.

Environment reference

VariableDefaultDescription
STRADEN_DOMAIN:80:80 serves plain HTTP. A hostname enables automatic HTTPS.
APP_URLhttp://localhost:8000Public URL, used in links and emails.
HTTP_PORT / HTTPS_PORT8000 / 8443Host ports mapped to the app container.
STRADEN_VERSIONlatestImage tag. Pin it in production.
STRADEN_ADMIN_NAME / _EMAIL / _PASSWORD—Create the first admin without the browser. Only used while there are no users.
DB_PASSWORDstradenPostgres password. Set before the first start.
APP_KEY, REVERB_APP_ID, REVERB_APP_KEY, REVERB_APP_SECRETgeneratedOverride the auto-generated secrets.
MAIL_*—SMTP settings for password reset and email verification. In-app notifications don't need mail.
LOG_LEVELinfoLog verbosity (logs go to stderr).

Admin accounts

There is no public registration. The admin adds users under Settings → Users.

To create the admin non-interactively, set STRADEN_ADMIN_EMAIL and STRADEN_ADMIN_PASSWORD before the first start. Locked out? Create or promote an admin and reset their password from the CLI:

BASH
docker compose exec app php artisan straden:admin you@example.com

A random password is printed unless you pass --password=. See Users & Security for managing accounts.

Secrets

APP_KEY and the Reverb credentials are generated on first start and stored in the storage volume at storage/app/.straden-secrets. AI provider keys are encrypted with APP_KEY — lose it and they become unreadable, so back this volume up.

Upgrading

BASH
docker compose pull
docker compose up -d

Migrations run automatically. Pin STRADEN_VERSION (e.g. 1.2.0) in production and bump it deliberately.

Backups

BASH
# Database
docker compose exec postgres pg_dump -U straden straden > straden.sql
# Scripts, run logs, cloned repositories and secrets
docker run --rm -v straden_storage:/data -v "$PWD":/backup alpine tar czf /backup/storage.tgz -C /data .
# Metrics
docker run --rm -v straden_influxdb:/data -v "$PWD":/backup alpine tar czf /backup/influxdb.tgz -C /data .

Load generator capacity

k6 runs inside the runner container, so the host's CPU and network bandwidth limit how much load you can generate. On a shared host, uncomment the deploy.resources block in compose.yaml:

YAML
runner:
  deploy:
    resources:
      limits: { cpus: "2", memory: 2g }

For the most accurate results, run Straden on a different machine from the system under test.

Building the image yourself

BASH
git clone https://github.com/kwasii1/straden && cd straden/deploy
docker compose -f compose.yaml -f compose.build.yaml up -d --build