On-prem deploy
On-prem, you bring your own Postgres, object storage, and model credentials — we never store your data. The server image migrates on boot and serves the API, auth, and web SPA from one origin.
Quickstart (Docker Compose)
cp deploy/.env.example deploy/.env
# Edit deploy/.env — at minimum set:
# BETTER_AUTH_SECRET (openssl rand -base64 48)
# LICENSE_JWT (from your vendor; without it the instance is read-only)
docker compose -f deploy/docker-compose.yml up -d --build
Then verify:
curl -fsS http://localhost:8080/healthz # {"status":"ok","mode":"onprem",...}
open http://localhost:8080/ # the web UI (same origin as the API)
up builds the image (context = repo root), starts Postgres 16 + the server, and the server migrates-on-boot then serves. Add --profile s3 to also start a bundled MinIO.
Bring your own Postgres
Point DATABASE_URL at your own database and drop the bundled service:
DATABASE_URL=postgres://user:pass@db.internal:5432/thespider \
docker compose -f deploy/docker-compose.yml up -d server # start only the server
The server needs a role that can create tables and (for RLS) SET ROLE app_role — a normal owner role of the target database is sufficient; migrate-on-boot creates app_role itself.
Bring your own object storage
Slice artifacts (rendered prompt / raw stdout / stderr) are content-addressed by sha256 provenance blobs — the parsed content already lives in reports. Default is the on-disk ARTIFACTS_DIR volume. For S3/MinIO/R2, set S3_BUCKET (+ endpoint/creds):
# bundled MinIO:
docker compose -f deploy/docker-compose.yml --profile s3 up -d --build
# then in .env: S3_BUCKET=thespider S3_ENDPOINT=http://minio:9000
# S3_ACCESS_KEY_ID=thespider S3_SECRET_ACCESS_KEY=thespider123
# create the bucket once (mc mb) — the server does not auto-create it.
See Data handling for the 90-day artifact lifecycle recipe.
Enroll a client
Mint a single-use enrollment code inside the container, then drive the Rust agent:
docker compose -f deploy/docker-compose.yml exec server \
bun run src/mint-enrollment-code.ts --org default --project default
# copy the printed `code:` value, then on a machine with model CLIs + a checkout:
echo "<code>" | thespider-agent login # server = http://<host>:8080 in config.toml
thespider-agent run # claim → run models locally → submit findings
thespider-agent gate --campaign <id> # CI-style pass/fail
The default project is campaign-ready at first boot — the image bundles a default methodology snapshot seeded as config_version 1, with the sonnet model enabled. Author your real buckets/passes/categories in the web UI (each save becomes a new immutable config_version).
Deploy on Kubernetes (Helm)
A minimal chart lives at deploy/helm/thespider (BYO Postgres — the chart deploys none):
helm install ts deploy/helm/thespider \
--set secrets.betterAuthSecret="$(openssl rand -base64 48)" \
--set secrets.licenseJwt="<jwt>" \
--set config.databaseUrl="postgres://user:pass@postgres:5432/thespider" \
--set image.repository=<your-registry>/thespider-server --set image.tag=<version>
# expose it:
helm upgrade ts deploy/helm/thespider --reuse-values \
--set ingress.enabled=true --set ingress.host=thespider.example.com
The chart renders a Deployment, Service, optional Ingress, a Secret (license/auth/S3/AI keys), and a PVC for the on-disk artifact store. helm lint + helm template validate it.
Back up
The Postgres database is the source of truth — it holds every finding, triage decision, config version, and usage event. Back it up on a schedule:
docker compose -f deploy/docker-compose.yml exec -T postgres \
pg_dump -U postgres thespider | gzip > thespider-$(date +%F).sql.gz
Artifacts (the thespider_artifacts volume / S3 bucket) are regenerable provenance — back them up only if you need the raw prompt/output blobs. The thespider_pg volume is the one that matters.
Upgrade
Pull/rebuild the new image and restart; migrate-on-boot applies additive migrations automatically:
docker compose -f deploy/docker-compose.yml up -d --build
To refresh methodology, pull an update bundle from the vendor (GET /v1/method-updates, license-JWT-authenticated) and apply it as a new immutable config version:
docker compose -f deploy/docker-compose.yml exec server \
bun run src/apply-methodology.ts --project default --file /path/to/snapshot.json
Verify the install
bash deploy/verify-onprem.sh
See deploy/air-gap.md for the fully-offline story.
Next steps
- Deployment modes — licensing & entitlements.
- Environment reference — every variable.