Files
jarvis-selfhost/.env.example
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

110 lines
5.3 KiB
Bash

# Jarvis — configuration. Copy to `.env` beside the compose file and fill in.
#
# cp .env.example .env
#
# Nothing here has a safe placeholder value: the four secrets must be generated, and the two URLs
# must be yours. The compose file refuses to start rather than booting with something wrong.
# ---------------------------------------------------------------------------
# Where your instance lives
# ---------------------------------------------------------------------------
# The address a browser reaches Jarvis on, scheme included and no trailing slash.
#
# This is the CORS decision. It accepts exactly ONE origin — not a list — and every request from
# anywhere else is refused, which presents as a sign-in page that cannot sign in.
WEB_ORIGIN=https://jarvis.example.com
# The address enrolled machines dial. Defaults to WEB_ORIGIN, which is right for a single-origin
# deployment. Set it separately only if the app and the API answer on different hostnames.
#PUBLIC_URL=https://jarvis.example.com
# Host port the web container publishes. Put your TLS terminator in front of it.
JARVIS_PORT=8080
# How many proxies rewrite X-Forwarded-For before a request reaches the API.
#
# One is the web container's own nginx, which is always there. So: 1 if nothing else fronts it, 2 if
# your own reverse proxy does — which is the usual case and the default. Raising it is the dangerous
# direction, because the API then trusts that many hops of a header the client can forge, and a caller
# can choose the address that lands in the audit log and in the session list.
TRUST_PROXY_HOPS=2
# ---------------------------------------------------------------------------
# Secrets — generate every one of these, never copy them from anywhere
# ---------------------------------------------------------------------------
# Postgres. Only ever used inside the compose network.
# openssl rand -base64 24
POSTGRES_PASSWORD=
# Session signing. Two different values, at least 16 characters each.
# openssl rand -base64 48
JWT_ACCESS_SECRET=
JWT_REFRESH_SECRET=
# THE ONE YOU CANNOT LOSE.
#
# Must decode to exactly 32 bytes:
# openssl rand -base64 32
#
# Every credential in the vault — SSH keys, API secrets, Microsoft 365 client secrets, the outbound
# mail password — is encrypted under this key with AES-256-GCM. It is not stored anywhere but here.
#
# Change it or lose it and none of that data can be read again, by you or by anyone. A database backup
# does not save you: the backup holds the ciphertext. Back this value up separately from the database,
# somewhere you would still have it if this host were gone. An instance whose key has changed keeps
# LOOKING configured — the rows are all there — and fails on every reveal.
VAULT_MASTER_KEY=
# ---------------------------------------------------------------------------
# The model
# ---------------------------------------------------------------------------
# Any OpenAI-compatible endpoint: OpenAI, a self-hosted gateway, a local server.
#OPENAI_BASE_URL=https://api.openai.com/v1
# Required. Jarvis will not start without it.
OPENAI_API_KEY=
# Must be a model your endpoint actually serves, and it should be a good one — this model is deciding
# what to run on production infrastructure.
#OPENAI_MODEL=gpt-4o
# minimal | low | medium | high. Higher costs latency and tokens and is worth it for real work.
#OPENAI_THINKING_LEVEL=medium
# ---------------------------------------------------------------------------
# Pinning (optional, recommended in production)
# ---------------------------------------------------------------------------
# Both services track `latest` unless you set these, so `docker compose pull && up -d` upgrades you.
# Pinning makes an upgrade a decision instead of a side effect of pulling. The app reports its real
# version either way — `latest` is a second name on the same image, not a build that forgot its number.
#JARVIS_IMAGE_API=git.luxit.be/luxit/jarvis-api:0.59.0
#JARVIS_IMAGE_WEB=git.luxit.be/luxit/jarvis-web:0.74.0
# Only read when the agent overlay is enabled, just below. Its version is the AGENT's, and moves
# independently of the two above — a Jarvis release usually does not change the agent at all.
#JARVIS_IMAGE_AGENT=git.luxit.be/luxit/jarvis-agent-dist:0.20.0
# ---------------------------------------------------------------------------
# The Jarvis agent (optional)
# ---------------------------------------------------------------------------
# Enrolling a machine downloads a compiled binary, which the api serves from a directory it can
# only read. `docker-compose.agent.yml` supplies that directory as a pullable image, so the release
# arrives the same way the rest of the stack does. Uncomment this and every later `docker compose`
# command picks up both files with no extra flags:
#
#COMPOSE_FILE=docker-compose.yml:docker-compose.agent.yml
#
# Leaving it off is a supported state, not a broken one: everything except the agent works, and the
# installer answers 503 saying no build is published. The SSH, Proxmox, Microsoft 365 and MikroTik
# connectors all reach machines without it.
#
# AGENT_RELEASE_DIR is set by that overlay and should NOT be set here — a value in this file would
# point the api at a path nothing populates, turning the honest 503 into a 404 per platform.
#AGENT_HEARTBEAT_INTERVAL_SEC=30
#RUN_SHUTDOWN_GRACE_SEC=25