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:latestUse 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
| Variable | What it is | Default |
|---|---|---|
QAITAI_URL | Control plane URL. Must be https unless it's a private or loopback address. | required |
QAITAI_TOKEN | Runner token (qrt_…), or QAITAI_TOKEN_FILE | required |
SLOTS | Parallel agent sessions, one browser each | 4 |
RUNNER_NAME | Name shown in the app | hostname |
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.