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>
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
# 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
|
||||
@@ -0,0 +1,8 @@
|
||||
# These files are read by Docker on a Linux host, whatever the machine that cloned them.
|
||||
#
|
||||
# Without this, a clone on Windows checks them out with CRLF, and the carriage return rides into
|
||||
# `.env` as part of a VALUE — Compose passes it through verbatim, so it ends up inside the database
|
||||
# password, the JWT secrets and the vault master key. The failure then surfaces as Postgres refusing
|
||||
# the connection, or as a vault that cannot decrypt what it wrote yesterday, with nothing anywhere
|
||||
# naming a line ending as the cause.
|
||||
* text=auto eol=lf
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
# Your instance's configuration, which holds every secret it has: the vault master key, the JWT
|
||||
# secrets, the database password and your AI provider's API key. NEVER commit it. `.env.example` is
|
||||
# the template and is the only one of these that belongs in a repository.
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Database dumps, which the README tells you to take before an upgrade. They contain every
|
||||
# conversation, asset and audit row on the instance — and the vault's ciphertext, which is one
|
||||
# leaked .env away from being plaintext.
|
||||
*.sql
|
||||
*.sql.gz
|
||||
@@ -0,0 +1,138 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Jarvis — the agent release, as a pullable image.
|
||||
#
|
||||
# OPTIONAL OVERLAY. The base stack runs perfectly without it; what it adds is the one feature a
|
||||
# self-hosted instance cannot otherwise have, because enrolling a machine downloads a compiled
|
||||
# binary and there is nowhere for a compose-only deployment to get one. This carries that release
|
||||
# as an OCI image, so it arrives through the same `docker compose pull` as the api and the web.
|
||||
#
|
||||
# Turn it on by naming both files. Either spelling works:
|
||||
#
|
||||
# docker compose -f docker-compose.yml -f docker-compose.agent.yml up -d
|
||||
#
|
||||
# or, so that a plain `docker compose ...` keeps working for every later command, put this in .env:
|
||||
#
|
||||
# COMPOSE_FILE=docker-compose.yml:docker-compose.agent.yml
|
||||
#
|
||||
# Upgrading is unchanged: `docker compose pull && docker compose up -d`. The publisher re-runs,
|
||||
# replaces the release in the volume, and the api picks it up WITHOUT a restart — digests are
|
||||
# computed from the bytes on disk on every request, not cached at boot.
|
||||
services:
|
||||
# Runs once per `up`, copies its payload into the shared volume, exits. Not a server.
|
||||
agent-releases:
|
||||
image: ${JARVIS_IMAGE_AGENT:-git.luxit.be/luxit/jarvis-agent-dist:latest}
|
||||
# Explicit, because the default would be wrong the moment somebody copies this block: a
|
||||
# restarting one-shot is an infinite loop, and Compose's own default policy is already "no".
|
||||
restart: "no"
|
||||
volumes:
|
||||
- agent_releases:/out
|
||||
|
||||
api:
|
||||
# NOTE THE COUPLING: until the publisher has exited 0, the api does not start. That is
|
||||
# deliberate — a release that failed to arrive should stop the deploy and say so, rather than
|
||||
# leave an instance quietly handing 404s to every installer somebody runs this week. The cost
|
||||
# is that an unreachable registry now blocks the whole stack, so if that trade is wrong for
|
||||
# you, drop these three lines and the api will simply serve no build until the volume fills.
|
||||
depends_on:
|
||||
agent-releases:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
# Read-only: the API serves these bytes to every managed machine and never writes here.
|
||||
- agent_releases:/srv/agent-releases:ro
|
||||
environment:
|
||||
AGENT_RELEASE_DIR: /srv/agent-releases
|
||||
|
||||
volumes:
|
||||
agent_releases:
|
||||
@@ -0,0 +1,134 @@
|
||||
# Jarvis — self-hosting stack.
|
||||
#
|
||||
# Everything runs from published images; nothing is built here and no source is needed.
|
||||
#
|
||||
# cp .env.example .env # then fill it in — see the comments in that file
|
||||
# docker compose pull
|
||||
# docker compose up -d
|
||||
#
|
||||
# Only the `web` service publishes a port. Its nginx serves the app and reverse-proxies /api and the
|
||||
# websocket to the internal `api` service, so your own TLS terminator has exactly one target and the
|
||||
# API is never reachable from outside this compose network.
|
||||
#
|
||||
# UPGRADING: `docker compose pull && docker compose up -d`. Both services track `latest` by default,
|
||||
# so that is the whole upgrade. Schema changes apply themselves when the api starts.
|
||||
#
|
||||
# `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 at build time. The footer in the app and
|
||||
# /version.json keep reporting 0.51.0 or whatever you actually pulled.
|
||||
#
|
||||
# To pin instead — recommended once you are in production, because it makes an upgrade a decision rather
|
||||
# than a side effect of pulling — set JARVIS_IMAGE_API and JARVIS_IMAGE_WEB in .env to explicit tags.
|
||||
name: jarvis
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: jarvis
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
|
||||
POSTGRES_DB: jarvis
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U jarvis -d jarvis"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
# Append-only so a restart does not lose the queue and the socket fan-out state.
|
||||
command: ["redis-server", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
|
||||
api:
|
||||
image: ${JARVIS_IMAGE_API:-git.luxit.be/luxit/jarvis-api:latest}
|
||||
restart: unless-stopped
|
||||
# The assistant runs long operations, and a deploy is the most common thing that interrupts one.
|
||||
# Given room to stop, the API aborts each loop, writes the partial answer with a note saying why
|
||||
# the transcript ends there, and marks the run interrupted so the next process picks it up.
|
||||
# Docker's 10s default is not enough. RUN_SHUTDOWN_GRACE_SEC must stay the smaller of the two.
|
||||
stop_grace_period: 60s
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
API_PORT: "4000"
|
||||
|
||||
# The address a browser reaches Jarvis on. This is the CORS decision: requests from any other
|
||||
# origin are refused, so a wrong value here presents as a sign-in page that cannot sign in.
|
||||
WEB_ORIGIN: ${WEB_ORIGIN:?set WEB_ORIGIN in .env}
|
||||
# The address baked into agent install commands and dialled by every enrolled machine. Usually
|
||||
# the same string as WEB_ORIGIN; separate because they answer different questions, and a wrong
|
||||
# value here does not fail at deploy time — it fails weeks later, on somebody else's server.
|
||||
PUBLIC_URL: ${PUBLIC_URL:-${WEB_ORIGIN}}
|
||||
|
||||
DATABASE_URL: postgresql://jarvis:${POSTGRES_PASSWORD}@postgres:5432/jarvis?schema=public
|
||||
REDIS_URL: redis://redis:6379
|
||||
|
||||
JWT_ACCESS_SECRET: ${JWT_ACCESS_SECRET:?set JWT_ACCESS_SECRET in .env}
|
||||
JWT_REFRESH_SECRET: ${JWT_REFRESH_SECRET:?set JWT_REFRESH_SECRET in .env}
|
||||
JWT_ACCESS_TTL: "900"
|
||||
JWT_REFRESH_TTL: "1209600"
|
||||
|
||||
# READ THE NOTE IN .env.example BEFORE CHANGING THIS. Every credential in the vault is
|
||||
# encrypted under it; lose it and they are gone, with no recovery of any kind.
|
||||
VAULT_MASTER_KEY: ${VAULT_MASTER_KEY:?set VAULT_MASTER_KEY in .env}
|
||||
|
||||
# Any OpenAI-compatible endpoint. Defaults to OpenAI itself.
|
||||
OPENAI_BASE_URL: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY:?set OPENAI_API_KEY in .env}
|
||||
OPENAI_MODEL: ${OPENAI_MODEL:-gpt-4o}
|
||||
OPENAI_THINKING_LEVEL: ${OPENAI_THINKING_LEVEL:-medium}
|
||||
|
||||
# How many proxies sit in front and rewrite X-Forwarded-For. ONE is the web container's own
|
||||
# nginx, which is always there — so 1 is right when nothing else fronts it, and 2 when your own
|
||||
# TLS terminator does. Raising it is the dangerous direction: the API trusts that many hops of a
|
||||
# header the client can forge, and too high lets a caller choose the IP that lands in the audit
|
||||
# log, in the session list and in the enrollment rate limit.
|
||||
TRUST_PROXY_HOPS: ${TRUST_PROXY_HOPS:-2}
|
||||
|
||||
AGENT_HEARTBEAT_INTERVAL_SEC: ${AGENT_HEARTBEAT_INTERVAL_SEC:-30}
|
||||
RUN_SHUTDOWN_GRACE_SEC: ${RUN_SHUTDOWN_GRACE_SEC:-25}
|
||||
|
||||
# Where the agent binaries live, if you have them. Leaving this unset is a supported state:
|
||||
# everything except the agent installer works, and the installer answers 503 saying no build is
|
||||
# published. See the README — a self-hosted instance has no way to produce these.
|
||||
AGENT_RELEASE_DIR: ${AGENT_RELEASE_DIR:-}
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- node
|
||||
- -e
|
||||
- "fetch('http://localhost:4000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
# First boot syncs the schema and runs the data backfills before it listens.
|
||||
start_period: 40s
|
||||
|
||||
web:
|
||||
image: ${JARVIS_IMAGE_WEB:-git.luxit.be/luxit/jarvis-web:latest}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- api
|
||||
ports:
|
||||
# Put your own TLS terminator in front of this. Jarvis speaks plain HTTP here on purpose and
|
||||
# reads X-Forwarded-Proto to know what the browser actually used.
|
||||
- "${JARVIS_PORT:-8080}:80"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
Reference in New Issue
Block a user