Self-Hosted Installation¶
1. Prerequisites¶
| Requirement | Version | Notes |
|---|---|---|
| Docker Engine | 24.x+ | docker --version |
| Docker Compose | v2.x (the docker compose plugin) |
docker compose version |
| PostgreSQL | 17 (bundled) | Provided as the postgres service via pgvector/pgvector:pg17 — no separate install needed unless you point RAI_DATABASE_URL at your own instance |
| Disk | ~2 GB+ | Server image (incl. baked-in ONNX embedding model) + growing PostgreSQL volume |
You do not need Python, uv, or Node installed on the host — everything
runs inside the container.
2. Get the source¶
3. Environment variables¶
The root docker-compose.yml sets sane defaults for every required
variable except the ones only you should know. Nothing needs to be
overridden for the default quick-start; the table below is for customizing
a real deployment.
| Variable | Set where | Default | Purpose |
|---|---|---|---|
RAI_DATABASE_URL |
docker-compose.yml (server env) |
postgresql+asyncpg://rai:dev@postgres:5432/rai |
AsyncPG connection string. Point this at an external managed PostgreSQL instead of the bundled postgres service by editing the compose file. |
RAI_ENV |
docker-compose.yml |
development |
Controls a small number of env-gated behaviors (e.g. migration execution path in entrypoint.sh). Self-hosted operators should leave this as-is unless they know they need Fly/Cloud Run semantics — those paths assume a platform-managed release step that does not exist here. |
RAI_PORT |
docker-compose.yml |
8080 |
Port uvicorn binds to inside the container; mapped to the host via the compose ports: entry. |
RAI_LOG_LEVEL |
docker-compose.yml |
DEBUG |
Lower to INFO or WARNING for a production-like deployment — DEBUG is chatty. |
RAI_COOKIE_SECURE |
docker-compose.yml |
false |
Set to true once you terminate TLS in front of the server (e.g. a reverse proxy) — session cookies then require HTTPS. |
UVICORN_RELOAD |
docker-compose.yml |
true |
Hot-reload on source changes. Turn this off ("false" or remove the line) for anything other than local development — it mounts packages/raise-server/src read-only into the container and watches it. |
RAI_STRIPE_SECRET_KEY / RAI_STRIPE_PRICE_MONTHLY / RAI_STRIPE_PRICE_ANNUAL / RAI_STRIPE_WEBHOOK_SECRET |
Shell env, forwarded via ${VAR:-} |
empty | Optional. Billing endpoints return 503 (not an error) when unset — self-hosted deployments typically don't need Stripe at all, since licensing/plan enforcement for a self-hosted instance is a local decision (see below). |
There is no .env.example specific to docker-compose.yml (the
.env.example at the repo root is for the separate team-infra compose file,
docker-compose.yaml, which also runs the rai-agent Telegram daemon — not
part of this self-hosted path). Override any of the variables above with a
shell export before docker compose up, or by adding an environment:
override in a docker-compose.override.yml.
4. Plans and licensing for self-hosted¶
Every authenticated member resolves to a plan (trial, community, pro,
team, enterprise) via MemberContext, driven by the org's row in the
licenses table — seed_dev.sql inserts an active team-plan license
(no expiry until 2027, no Stripe involved). Any member with a resolved plan
— community and up — is sufficient to call every endpoint in this story
(/api/v2/export/*, /api/v2/metrics, /api/v2/adoption,
/api/v2/audit): none of them impose a paid-tier minimum beyond
authentication. There is no external license server call required — no
network egress beyond what you configure yourself.
5. Networking¶
postgresis not exposed outside the Docker network by default beyond the5432:5432host port mapping already indocker-compose.yml— remove that mapping if you don't need host-sidepsqlaccess.serverlistens on8080inside the container, mapped to host8080. Put a reverse proxy (nginx, Caddy, Traefik) in front for TLS termination in any deployment reachable outsidelocalhost; setRAI_COOKIE_SECURE=trueonce you do.- No outbound network calls are required at runtime for the endpoints this story adds (export/metrics/audit/adoption are pure PostgreSQL reads). Other parts of the image have optional outbound dependencies only when explicitly configured — Stripe (billing) and the Atlassian/Google OAuth identity-broker flows are the two examples in this compose file; leave their env vars unset to keep the deployment fully offline.
6. First-run verification¶
docker compose up -d --build
docker compose logs -f server # watch migrations run, then "Uvicorn running on..."
curl http://localhost:8080/health
A healthy response has "database": "connected". If migrations are still
running you'll see connection refused briefly — see
troubleshooting.md.
Continue to docker-compose.md for a field-by-field breakdown of the compose file, or straight to export-api-usage.md to try the bulk export API.