Self-hosting kinora

June 16, 2026 ยท View on GitHub

Run the whole stack (Postgres + server + dashboard) with one docker compose, on a single origin, with trace artifacts on a local volume.

Quickstart

From this selfhost/ directory:

cp .env.example .env
# edit at least: PUBLIC_URL, AUTH_SECRET, POSTGRES_PASSWORD
docker compose up -d --build

Open PUBLIC_URL (default http://localhost:8080) and create your account. The first user owns their workspace; invite teammates from Settings.

What's here

  • docker-compose.yml - Postgres, a one-shot migrate, the server, and the web container.
  • nginx.conf - the web container's reverse proxy (serves the dashboard + trace viewer, proxies the API to the server).
  • .env.example - all configuration.

Images are built from the repo root via the per-package Dockerfiles; the compose build.context is ...

How it works

Everything is one origin. The web container serves the dashboard and the embedded trace viewer, and reverse-proxies /api, /trpc, and /artifacts to the server. So there is no CORS to configure and the session cookie stays host-only (COOKIE_DOMAIN empty). Postgres data and trace artifacts live in named volumes (kinora-db, kinora-artifacts). Migrations run automatically (the migrate service) before the server starts.

Configuration (.env)

VarRequiredNotes
PUBLIC_URLyesThe URL users reach kinora at. Drives links, cookies, and artifact URLs.
WEB_PORTnoHost port for the web container (default 8080). Match PUBLIC_URL.
AUTH_SECRETyesSession secret. openssl rand -hex 32.
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DByesDatabase credentials.
SMTP_*noEnables email verification, password reset, invitations, and email alerts.
GOOGLE_* / GITHUB_*noSocial login. Leave empty for email + password only.
S3_*noUse an S3-compatible store instead of the local volume.

Self-host runs with KINORA_CLOUD=false (no billing; every feature, including alerts, is unlimited).

Send your tests

Point the reporter or CLI at your PUBLIC_URL:

# reporter (in playwright.config.ts: reporter: [['@kinora/reporter', { project: { slug: 'web-app' } }]])
KINORA_URL=https://kinora.example.com KINORA_TOKEN=<token> npx playwright test

# CLI
npx @kinora/cli upload results.json --project web-app \
  --url https://kinora.example.com --token <token>

Create the token in the dashboard under Settings -> Workspace. See the reporter and cli docs for all options.

Own domain and HTTPS

Set PUBLIC_URL to your public https URL (e.g. https://kinora.example.com) and put the web container behind your own TLS proxy (Caddy, Traefik, nginx, a load balancer, ...) forwarding to WEB_PORT. Rebuild the web image after changing PUBLIC_URL (it is baked at build time): docker compose up -d --build web.

Upgrades

git pull
docker compose up -d --build

Migrations apply automatically on start.

Backups

Two volumes hold all state:

  • kinora-db - the Postgres database.
  • kinora-artifacts - uploaded trace.zip / screenshots / videos.

Back them up with your usual volume backup workflow (or pg_dump for the database).