Sync the self-hosting stack

This commit is contained in:
2026-10-22 08:56:35 +02:00
parent 6a2b67364b
commit b1fa205ebf
7 changed files with 105 additions and 110 deletions
+28 -41
View File
@@ -305,9 +305,9 @@ parameter stops the api with `DATABASE_URL: unsupported parameter "<name>"` rath
ignored.
`sslmode=require` encrypts without checking the server's certificate, as it always has here;
`sslaccept=strict` checks it and the host name. `verify-ca` and `verify-full` check it too — before
api 1.0.0 they were read as `prefer` — so a URL that carried one may now refuse a certificate the
container cannot verify: mount the CA and name it with `sslrootcert`. The migration holds a session
`sslaccept=strict` checks it and the host name. `verify-ca` and `verify-full` check it too, so a URL
that carries one refuses a certificate the container cannot verify: mount the CA and name it with
`sslrootcert`. The migration holds a session
lock, so it needs a direct connection to Postgres, not PgBouncer in transaction mode; `pgbouncer=true`
in the URL is warned about.
@@ -388,41 +388,28 @@ prerequisite rather than a precaution.
docker compose exec -T postgres pg_dump -U jarvis jarvis | gzip > jarvis-$(date +%F).sql.gz
```
### Upgrading from the TypeScript releases (api 0.x)
### Upgrading from 1.x
api 1.0.0 and web 1.0.0 are Jarvis rewritten on .NET. The images keep their names and their channels,
so the upgrade is the usual one, with four things to know first.
**2.0 starts from an empty database; it does not upgrade a 1.x one.** Its schema was rebuilt, and
there is no migration from the 1.x schema. Pointed at a 1.x database, the api changes nothing,
logs a `[migrate]` line containing `it was not created by this version of Jarvis`, and restarts
into the same refusal.
- **Be on api 0.151.0 first** — the last 0.x release — and let it start once. A database it has not
migrated is refused by 1.0.0 without a change: the api logs `[migrate] This database was built by
the TypeScript API, but not by its last release`, the release to install and what is missing, and
restarts into the same refusal. Pin `JARVIS_IMAGE_API=git.luxit.be/luxit/jarvis-api:0.151.0` in
`.env`, `docker compose up -d`, wait until it serves, remove the pin and `docker compose up -d`
again.
- **Move the api and the web together** if you pin: `JARVIS_IMAGE_API` and `JARVIS_IMAGE_WEB` both.
A 1.x api behind a 0.x console, or the reverse, works without live updates.
- **Take the new `docker-compose.yml`.** Two lines changed: `init` runs `jarvis init-secrets` and the
api's healthcheck `jarvis healthcheck`. Your current file keeps working — the 1.x api image still
answers the three `node` commands the 0.x files give it, and refuses any other — until a later
release removes them, with `/usr/local/bin/migrate.sh` and `/usr/local/bin/entrypoint.sh`; its
CHANGELOG entry will say so.
- **Nothing to add to `.env`.** Every variable keeps its name and its meaning, `NODE_ENV` included.
To move an instance to 2.0, start it on a new, empty database and install it again:
The first 1.x start records where the schema stands (it creates `__EFMigrationsHistory` and changes
nothing else) and takes seconds. Open tabs lose live updates until they are reloaded; agents
reconnect by themselves.
1. Note what you will re-enter: organizations, users, connections, the vault's secrets. The 1.x dump
cannot be imported into 2.0.
2. `docker compose down`, then remove the database volume (`docker volume rm jarvis_postgres_data`)
or point `DATABASE_URL` at a new database. Keep `.env` and the `jarvis_secrets` volume if you like —
a new vault key is just as good, since the vault starts empty.
3. Take the new `docker-compose.yml`, `docker compose pull && docker compose up -d`, and go through
the installation wizard.
4. Enroll your machines again: an agent's credentials lived in the old database. Run the install
command the console gives you on each machine: it enrolls the machine with the new instance,
keeping the agent's key.
**On Kubernetes**, pin both digests in one change, with the new manifests: `01-secret-job.yaml` runs
`jarvis mint-k8s-secret` (and no longer sets `NODE_EXTRA_CA_CERTS`), `03-migrate-job.yaml` runs
`jarvis migrate`, and `04-api.yaml` recreates the api for this release — every old pod stops before
a new one starts, a gap of about thirty seconds, once — and rolls it again from the next. Overlays of
your own that call `/usr/local/bin/migrate.sh` keep working until that release.
**The way back**, until the first release after 1.0.0 whose entry says it changes the schema: pin
both previous images and either set `SCHEMA_ACCEPT_DATA_LOSS=true` for one start — the 0.x api then
drops `__EFMigrationsHistory` and nothing else; its log names what it drops, and anything else in
that list means: stop, and restore — or set `JARVIS_SKIP_MIGRATIONS=true` until you upgrade again.
After that release, the dump is the way back.
**On Kubernetes**, the same: delete the database (or its PVCs), apply the new manifests, and let the
migration Job create the schema.
### Channels
@@ -696,7 +683,7 @@ wrong on the screen that asks for it.
| Everything works but one kind of thing cannot be created | A limit is full — the community edition's, or your licence's. The message names which. See below. |
| An agent installer answers 503 | No agent build is published — the overlay is off. That is a supported state. |
| The remote terminal works and remote desktop never connects | The proxy forwards `/api/agents/ws` but not the paths under it. The media socket is `/api/agents/ws/desktop` and needs the upgrade too. |
| api restarts in a loop, logs `This database was built by the TypeScript API, but not by its last release` | The upgrade skipped a release. Install the one it names, let it start, then this one — see "Upgrading from the TypeScript releases". |
| api restarts in a loop, logs `it was not created by this version of Jarvis` | A 1.x database: 2.0 starts from an empty one — see "Upgrading from 1.x". |
| api restarts in a loop, logs `DATABASE_URL: unsupported parameter` | A parameter the api does not read. The list it does read is under "Your own Postgres". |
| The console stays blank behind your proxy; the browser's console names a Content Security Policy | Your proxy's policy refuses the console's scripts — see "Your reverse proxy has three requirements". |
| A remote desktop session opens and ends immediately | Almost always the notice. It ends by design if the banner cannot be kept on top, if the person refuses, or if nobody answers the request within the minute. The end reason on the session says which. |
@@ -718,7 +705,7 @@ minutes, and it turns every case below into somebody else clicking a button.
```sh
docker compose exec -T postgres psql -U jarvis -d jarvis \
-c "UPDATE \"User\" SET \"platformRole\" = 'SUPER_ADMIN' WHERE email = 'colleague@example.com';"
-c "UPDATE \"Users\" SET \"PlatformRole\" = 'SuperAdmin' WHERE \"Email\" = 'colleague@example.com';"
```
They then reset the locked-out password under **Admin Center → Users**.
@@ -738,8 +725,8 @@ Then write it, and make sure the account is active and privileged:
```sh
docker compose exec -T postgres psql -U jarvis -d jarvis -c \
"UPDATE \"User\" SET \"passwordHash\" = '<the \$argon2id\$… string>', \"isActive\" = true,
\"platformRole\" = 'SUPER_ADMIN' WHERE email = 'you@example.com';"
"UPDATE \"Users\" SET \"PasswordHash\" = '<the \$argon2id\$… string>', \"IsActive\" = true,
\"PlatformRole\" = 'SuperAdmin' WHERE \"Email\" = 'you@example.com';"
```
Quote the hash in single quotes — it contains `$` characters your shell would otherwise eat.
@@ -752,9 +739,9 @@ demanding one:
```sh
docker compose exec -T postgres psql -U jarvis -d jarvis <<'SQL'
DELETE FROM "WebAuthnCredential" WHERE "userId" = (SELECT id FROM "User" WHERE email = 'you@example.com');
DELETE FROM "UserTotpCredential" WHERE "userId" = (SELECT id FROM "User" WHERE email = 'you@example.com');
UPDATE "User" SET "mfaEnabled" = false, "mfaEnabledAt" = NULL WHERE email = 'you@example.com';
DELETE FROM "WebAuthnCredentials" WHERE "UserId" = (SELECT "Id" FROM "Users" WHERE "Email" = 'you@example.com');
DELETE FROM "UserTotpCredentials" WHERE "UserId" = (SELECT "Id" FROM "Users" WHERE "Email" = 'you@example.com');
UPDATE "Users" SET "MfaEnabled" = false, "MfaEnabledAt" = NULL WHERE "Email" = 'you@example.com';
SQL
```