qaitai docs

Runner behind a VPN or firewall

Run workers inside your network with outbound HTTPS only. No inbound ports, no database credentials.

A remote-mode runner executes runs next to the app under test (staging, localhost, a private VPC). It works with qaitai Cloud or your own instance.

It needs exactly two settings, the control plane's URL and a runner token, and holds no database credentials, no master key and no Hatchet token. It only makes outbound HTTPS calls to the control plane, plus the model API, its browser and the app under test. It works behind NAT or a VPN.

Create a runner token

In the app, open Workers and add a runner. Copy the qrt_… token: it is shown once and stored only as a hash.

Start the runner

docker run -d --name qaitai-runner --restart unless-stopped --shm-size 1g \
  -e QAITAI_URL=https://app.tryqaitai.com \
  -e QAITAI_TOKEN=qrt_... -e SLOTS=4 \
  ghcr.io/qaitai/runner-chromium:latest

Use your own instance's URL instead of app.tryqaitai.com when self-hosting. Hardening that works with both images: --read-only --tmpfs /tmp --cap-drop ALL --security-opt no-new-privileges.

Run against a private URL

Start a run with the self-hosted runtime. Self-hosted runs may target localhost, private addresses and any public host, because they run on your runner and your IP.

Settings

VariableWhat it isDefault
QAITAI_URLControl plane URL. Must be https unless it's a private or loopback address.required
QAITAI_TOKENRunner token (qrt_…), or QAITAI_TOKEN_FILErequired
SLOTSParallel agent sessions, one browser each4
RUNNER_NAMEName shown in the apphostname

Optional: STEEL_BASE_URL / STEEL_API_KEY (your own Steel; the default is local Chromium in the runner-chromium image), STEEL_PUBLIC_URL, and your own model key (ANTHROPIC_API_KEY, AI_GATEWAY_API_KEY, or OPENAI_COMPATIBLE_BASE_URL + OPENAI_COMPATIBLE_API_KEY).

Model keys

A remote runner never receives the control plane's managed key. It uses the workspace's BYOK key when the run is BYOK, otherwise its own env key. On qaitai Cloud, runs on your own runner must use BYOK.

How it talks to the control plane

The runner enrolls, heartbeats every 30 seconds and long-polls for queued runs of its own workspace, claims one atomically and streams progress back with a short-lived per-job token. Details: Runner API.

Rotating the token or deleting the runner cuts it off at its next call. A runner that stops heartbeating for 5 minutes has its running jobs errored out.

On this page