Files
jarvis-selfhost/README.md
T
antoineandClaude Opus 5 137174e184 Initial commit: the self-hosting stack
Everything needed to run Jarvis on your own Docker host, and nothing else. The images are
published; this is the compose that arranges them, the environment they read, and the
prose explaining which values are load-bearing.

It lives in its own repository rather than in a directory of the product's, because the
audience is different in the one way that matters: a self-hoster has no access to the
source and no reason to want it. Handing them a monorepo path to browse would be handing
them a page of files they cannot clone, next to the four they can.

WHAT IS HERE:

- `docker-compose.yml` — postgres, redis, the api and the web. Only the web publishes a
  port; it reverse-proxies /api and the websocket internally, so a TLS terminator in
  front has exactly one target and the API is never reachable from outside the network.
- `docker-compose.agent.yml` — the optional overlay that supplies the compiled agent
  binaries as a pullable image. Off by default, and the README says why leaving it off is
  a supported state rather than a broken one.
- `.env.example` — every comment in it is load-bearing. The VAULT_MASTER_KEY note
  especially: it has no recovery, and a database backup does not protect what it wraps.
- `.gitignore` — .env and database dumps, because the first thing anyone does with this
  repository is fill one of those with secrets and the second is to forget it is there.

The README states the limitations plainly instead of leaving them to be discovered: SSH
host keys are not verified, access tokens survive revocation for up to 15 minutes,
self-registration is open by default and the first account created becomes super-admin,
both containers run as root, and /api/health answers 200 while the database is down.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 21:54:48 +02:00

139 lines
6.8 KiB
Markdown

# Self-hosting Jarvis
Jarvis is an AI-assisted infrastructure administration platform for MSPs. This repository runs it from
published container images — no source, no build, no account with the project.
## What you need
- Docker with Compose v2, on anything Linux.
- A hostname and a TLS terminator in front of it. Jarvis speaks plain HTTP and reads
`X-Forwarded-Proto`; it does not manage certificates.
- An API key for an OpenAI-compatible endpoint.
- Roughly 2 GB of RAM for the stack and room for Postgres to grow.
## Install
```sh
git clone https://git.luxit.be/Luxit/jarvis-selfhost.git
cd jarvis-selfhost
cp .env.example .env
$EDITOR .env # every comment in it is load-bearing; the secrets note especially
docker compose pull
docker compose up -d
```
First boot syncs the database schema and runs its data backfills before the API listens, so give it
about a minute. Then point your reverse proxy at `JARVIS_PORT` and open the app.
**The first account created becomes super-admin.** Self-registration is open by default, so sign up
immediately after the stack is up and then close registration under Settings → Platform → General.
Leaving it open means anyone who reaches the sign-in page gets an account.
## Your reverse proxy has two requirements
Both are the kind that produce confusing symptoms rather than clean errors.
- **Forward the WebSocket upgrade.** Without it the chat cannot stream and no agent can connect.
- **Give it a long read timeout** — 300s or so. A reasoning model can go 90+ seconds without emitting
a byte, and a 60s default cuts the response mid-stream. The client sees a connection reset rather
than a timeout, which reads like a bug in Jarvis.
## Upgrading
```sh
docker compose pull && docker compose up -d
```
That is the whole upgrade: both services track `latest`. Schema changes apply themselves when the api
starts, and the api and the web are versioned independently — their numbers are not meant to match,
because usually only one side changed.
**`latest` does not mean the app forgets which build it is.** The tag is a second name on the same image
as the version tag, and the version is stamped into the image when it is built — so the footer in the
app and `/version.json` keep reporting the real number, whichever name you pulled it under. That is
what lets you tell somebody which build you are on when something goes wrong.
Once you are in production, consider pinning: set `JARVIS_IMAGE_API` and `JARVIS_IMAGE_WEB` in `.env`
to explicit tags. It makes an upgrade a decision rather than a side effect of pulling.
Take a database dump before an upgrade that moves the api's minor version:
```sh
docker compose exec -T postgres pg_dump -U jarvis jarvis | gzip > jarvis-$(date +%F).sql.gz
```
## What you get, and what you do not
Working: the assistant with its tool-calling loop, plan-level approvals for destructive operations,
the encrypted vault, the asset registry, multi-tenant RBAC, real-time conversations, documents and
exports, the audit trail, and the connectors — SSH, Proxmox, Microsoft 365 and MikroTik.
**The Jarvis agent is an optional overlay, off by default.** Enrolling a machine downloads a compiled
binary that the api serves from `AGENT_RELEASE_DIR`, and a compose-only deployment has no way to
produce one. `docker-compose.agent.yml` supplies it as a pullable image instead. Leaving it off is a
supported state rather than a broken one: everything else works, the installer answers 503 saying no
build is published, and the connectors above reach machines without it.
## The agent
Turn it on by adding one line to `.env`, so that every later `docker compose` command picks up both
files with no extra flags:
```sh
COMPOSE_FILE=docker-compose.yml:docker-compose.agent.yml
```
then `docker compose pull && docker compose up -d`. A one-shot `agent-releases` service copies the
release into a volume the api reads, and exits. From there, Settings → Agents hands you the install
one-liner for each platform.
Three things worth knowing about it:
- **Until that publisher exits cleanly, the api does not start.** That is deliberate — a release that
failed to arrive should stop the deploy loudly rather than leave you handing 404s to every installer
you run this week. The cost is that an unreachable registry blocks the whole stack. The comment in
the file names the three lines to drop if you would rather it degraded quietly.
- **Upgrading it does not restart anything.** The api computes each download's checksum from the bytes
on disk on every request, so a new release in the volume is served immediately.
- **The agent version is its own number.** It moves independently of the api and the web, and a Jarvis
release usually does not touch it at all. Pin it with `JARVIS_IMAGE_AGENT` when you pin the others.
The agent runs as root on Linux and macOS and as LocalSystem on Windows, deliberately — its purpose is
to administer the machine. What it may actually *do* is decided by Jarvis' autonomy policy and its
approval gates, not by the account it runs under. Read that section of the main documentation before
enrolling anything you care about.
## Things worth knowing before you trust it with production
These are deliberate and documented rather than surprises waiting to be found.
- **`VAULT_MASTER_KEY` has no recovery.** Read the note in `.env.example`. A database backup does not
protect the vault — the backup holds ciphertext encrypted under that key.
- **SSH host keys are not verified.** Every SSH connection trusts whatever key answers. This is the
one gap in the execution path with no compensating control.
- **Access tokens cannot be revoked.** Revoking a session or changing a password invalidates refresh
tokens; a stolen access token stays valid for up to 15 minutes.
- **The api must run as a single replica.** In-flight runs, pending approvals and presence live in
per-process memory. Scaling it out silently drops cancels and approvals answered on the wrong one.
- **Both containers run as root**, and `/api/health` answers 200 with `status: "degraded"` when the
database is unreachable, so the container healthcheck alone is not a liveness signal for the DB.
- The assistant executes real operations on real infrastructure. Destructive ones require in-chat
human approval; mutating ones do not. Decide your autonomy level per conversation accordingly.
## Backups
Postgres holds everything except the vault key. Two volumes matter:
```sh
docker compose exec -T postgres pg_dump -U jarvis jarvis | gzip > jarvis.sql.gz
```
Plus `VAULT_MASTER_KEY`, stored somewhere that is not this host. A dump without the key is a database
whose credentials cannot be read.
## Licence
The images are provided as-is with no warranty, no support and no commitment to future availability.
The source is not public and no rights to it are granted. Ask the maintainer before deploying this
commercially or for third parties.