Self-hosting Vera
Run Vera on your own infrastructure: prerequisites, production build, the configuration that matters, backups, and the two settings to get right.
Vera runs on your own infrastructure. In self-hosted mode every feature is on — there is no plan gating and no billing — and no test data leaves your network.
What you need
- Node 20 or newer, and
pnpm - PostgreSQL — the single source of truth for projects, tests, runs and history
- Playwright browsers, installed once
- Optional: S3-compatible object storage for run artifacts (videos, screenshots, diffs). Without it, artifacts are written to local disk.
- Optional: Google Chrome, if you want real Chrome mode
Development stack
The repository ships a compose file with Postgres and MinIO (an S3-compatible store):
docker compose up -d # Postgres on :5439, MinIO on :9000 (console :9001)
pnpm setup # install deps, build the DB package, install browsers
pnpm dev # API on :4545, dashboard on :4546Production
pnpm install
pnpm playwright:install
pnpm build # builds shared → db → server + dashboard
pnpm start # serves the API and the built dashboard on one port (:4545)pnpm start serves everything from a single origin — API, dashboard, and run
artifacts — so there is no CORS configuration and no second deploy target.
Migrations are committed to the repository and applied automatically on startup, so a deploy does not need a separate migrate step.
Configuration
Every environment variable goes through one validated schema. .env.example
documents all of them; these are the ones that matter first.
Required
| Variable | Purpose |
|---|---|
DATABASE_URL | Postgres connection string. |
QA_AUTH_DUAL | Whether built-in auth runs alongside Clerk. |
QA_BLOCK_PRIVATE_HOSTS | Whether to refuse loopback/RFC1918 targets. See below. |
QA_ALLOW_SETUP_COMMANDS | Whether project setup actions may run shell commands. |
Commonly set
| Variable | Purpose |
|---|---|
PORT / HOST | Where the server listens. Defaults to 127.0.0.1:4545. |
QA_ENCRYPTION_KEY | Key for sealing stored credentials and BYOK AI keys. |
S3_* | Object storage for artifacts. Omit to use local disk. |
QA_MAX_BROWSERS | Cap on concurrent browsers process-wide. |
CLAUDE_CLI_PATH | Path to the claude binary, for the key-free AI provider. |
Many runtime knobs are additionally admin-editable from the /admin console
(browser cap, scheduler tick, recorder idle timeout, private-host policy, AI
provider defaults) — env supplies the default, the database overlays overrides, and
no restart is needed.
A few are deliberately env-only and cannot be changed over the API: the port and
host, DATABASE_URL, the S3 credentials, the encryption key and CLAUDE_CLI_PATH.
That last one names a binary the server spawns, so making it editable over HTTP
would be a remote-code-execution vector.
Two settings to get right
HOST. The API has no authentication in local mode, so it binds 127.0.0.1 by
default. Setting HOST=0.0.0.0 exposes it to the network — do that only where the
network is trusted, or behind a reverse proxy that authenticates.
QA_BLOCK_PRIVATE_HOSTS. Vera navigates to URLs you give it, and testing your
own app on localhost is the core use case, so loopback and private ranges are
allowed by default. Cloud-metadata and unspecified addresses are always blocked.
On a shared or multi-tenant host, set this to true — otherwise a tenant can point
a test at your internal network.
Data & storage
| What | Where |
|---|---|
| Projects, tests, runs, history | Postgres |
| Videos, failure screenshots, visual diffs | S3, or data/ on local disk |
Any S3-compatible store works. One flag matters and is easy to get wrong:
S3_FORCE_PATH_STYLE. MinIO needs path style (endpoint/bucket/key) and is the
default whenever S3_ENDPOINT is set; Railway Buckets, Tigris and AWS want
virtual-hosted (bucket.endpoint/key) and need S3_FORCE_PATH_STYLE=false. Your
store's own credentials page states which it requires — it is not safely inferable from
the endpoint.
The server serves only the videos, screenshots and diffs subdirectories of the
data directory. That is deliberate and worth preserving if you change it: serving the
whole directory would expose anything else kept there.
Backups
Postgres holds everything that cannot be regenerated. pg_dump is safe while the
server is running:
pg_dump "$DATABASE_URL" > vera-$(date +%F).sqlRestore into a fresh database and point DATABASE_URL at it. Artifacts are large and
regenerable by re-running, so back them up only if run history matters to you as
evidence.
The dump contains project credentials and sealed keys. Treat it as a secret.
Running hosted Vera rather than self-hosting? This section is the self-hosting answer, where you own the database and can decide a periodic dump is enough. The operator-side story — provider snapshots, PITR, artifact protection, RPO/RTO and a repeatable restore rehearsal — is
disaster-recovery.md.
Whichever you run: sealed columns in the dump are AES-256-GCM, so restoring under a
different QA_ENCRYPTION_KEY does not degrade gracefully — the rows restore fine and
then every read of a credential throws. Back the key up somewhere that survives losing
the machine, or the backup is only half a backup.
Keeping it running
Run it under whatever supervisor you already use — systemd, PM2, a container orchestrator. Two things to configure whichever you pick:
- Graceful shutdown. On SIGINT/SIGTERM Vera stops the scheduler, ends recorder sessions, closes browsers, then closes the server, with a hard deadline. Give it a stop timeout of at least 15 seconds so in-flight runs finish writing rather than being killed mid-write.
- Restart on failure, and start on boot.
Retention
Run retention is off by default: history accumulates until you set a policy. On a long-lived instance that is worth configuring — runs and their artifacts are the bulk of the storage growth. See Analytics.
AI
AI features are bring-your-own-key. Self-hosted, you can either configure a provider
key or use the local claude CLI as a key-free provider by pointing
CLAUDE_CLI_PATH at it. Nothing is sent to a Vera-operated service either way.
See also
- Getting started — first project and first green test
- The local agent — the alternative: cloud control plane, local execution
- CI integration — running your instance from a pipeline
- Test engines — adding a Selenium grid