nessie

Installere Nessie

Kjør Nessie på infrastruktur du velger, fra én enkelt maskin til en administrert sky.

Dette må være på plass før du starter

Nessie er et pnpm-monorepo med Node-tjenester og to statiske pakker. Uansett hvordan du kjører det, må de samme fire tingene finnes først.

  • PostgreSQL med pgvector. Ikke valgfritt, og ikke noe du kan bytte ut – migreringene kjører CREATE EXTENSION vector og oppretter vector(1024)-kolonner. Produksjon kjører pgvector/pgvector:pg17.
  • Node 22 og pnpm. Alle Dockerfiler i infrastructure/docker/ bygger på node:22-slim, og repositoriet låser pakkehåndteringen i rot-package.json (pnpm@10.22.0).
  • Et OpenAI-kompatibelt modell-endepunkt og en nøkkel til det. Agenter og embeddings går begge gjennom det. Se «Konfigurere inferens» nedenfor.
  • S3-kompatibel objektlagring, for alle installasjoner som ikke er det lokale utviklingsmiljøet. Opplastinger på lokal disk avvises utenfor local-modus, og avvisningen er en oppstartsfeil, ikke en nedgradert oppstart – se «Én maskin, eller en administrert sky».

Docker og en reverse proxy trengs for containerveien beskrevet lenger ned, og et domene pluss TLS for alt som kan nås fra internett.

Maskinvaredimensjonering – minimum CPU, minne og disk for et gitt antall personer – står ikke noe sted i repositoriet, så denne siden oppgir det heller ikke.

Komponentene, og hvordan de henger sammen

KomponentHva det erEkstern tilgang
api/Fastify HTTP/WebSocket-API-et. Alle klienter snakker med dette og ingenting annet.Ja
worker/Agentorkestrering og bakgrunnskjøringer. Henter jobber fra køen og binder ingen port.Nei
admin/Produktgrensesnittet – en statisk pakke bygget med Vite og servert av nginx.Ja
web/Den offentlige nettsiden. Statisk, valgfri, og uavhengig av å kjøre produktet.Ja
PostgreSQLDatabasen, jobbkøen og sanntidskanalen – alle tre.Nei
ObjektlagringVedlegg, avatarer og filer i kunnskapsbasen. S3-kompatibel; MinIO i produksjon.Nei
gateway/Et valgfritt push-relé for APNs og FCM. Er av med mindre du slår det på bevisst.Ja

API-et og worker-en er ett image. De to pakkene er tett sammenkoblet, så Dockerfile.app bygger hele kodebasen én gang, og worker-containeren overstyrer kommandoen til node worker/dist/index.js. I local-modus finnes det ingen worker-container i det hele tatt: API-et kjører worker-en innebygd i sin egen prosess.

Det finnes ingen Redis. Jobbkøen og sanntidstransporten er begge basert på Postgres – et bevisst valg, ikke en utelatelse. Google Cloud-treet sletter sine Pub/Sub- og Redis-moduler av samme grunn.

Porter

I lokal utvikling er API-et som standard på 5454 og admin på 5455. En utsjekk kan ta sitt eget par ved å sette NESSIE_API_PORT og NESSIE_ADMIN_PORT, i miljøet eller i repositoriets .env; alle verktøy i repositoriet, nettleser-testsuitene inkludert, leser de samme to verdiene. Velg paret før du starter, og behold det: flytter du en kjørende tjeneste til en annen port, snakker admin med feil API.

Produksjon er en annen sak, og den regelen endres ikke av det. API-containeren lytter internt på 5554 (satt med NESSIE_API_PORT) og push-reléet på 5556, begge bak reverse proxyen.

Kjøre det på én maskin, for utvikling

Repositoriet har en Compose-fil med bare en database i, og det er alt den lokale løkken trenger.

pnpm install
docker compose -f infrastructure/compose/docker-compose.yml up -d postgres

Den containeren publiserer Postgres på 55432, med bruker, passord og database som alle heter nessie. Legg tilkoblingsstrengen i en .env i rota av repositoriet – API-ets dev-script leser den – og kjør deretter migreringene og bygg worker-en én gang, fordi API-et i lokal modus laster worker-en fra sin bygde dist:

DATABASE_URL=postgresql://nessie:nessie@localhost:55432/nessie

pnpm --filter @nessie/api prisma:migrate:deploy
pnpm --filter @nessie/worker build
pnpm dev

pnpm dev kjører API-et og admin parallelt med hot reload, på 5454 og 5455. Sjekk at API-et svarte med GET /api/health.

Postgres, og kravet til pgvector

Tre utvidelser opprettes av migreringene selv – vector, pg_trgm og pgcrypto – så rollen som kjører dem må ha lov til å opprette utvidelser. På en administrert Postgres er det det første du bør sjekke.

Vektorbredden er en del av skjemaet, ikke en innstilling. thoughts.embedding, thought_recalls.query_embedding og knowledge_page_chunks.embedding er vector(N)-kolonner, og N er oppgitt én gang som EMBEDDING_DIMENSIONS i packages/schemas/src/embedding.ts – i dag 1024, den opprinnelige bredden til embedding-modellen produksjon bruker. Hver embed-forespørsel sender den bredden, så en leverandør som svarer med en annen bredde, feiler høylytt i stedet for å skrive vektorer databasen avviser. Å gå over til en embedding-modell med en annen bredde betyr å endre den konstanten, skrive en migrering som endrer typen på de tre kolonnene, og embedde på nytt: vektorer med ulik bredde kan ikke konverteres, så migreringen nuller dem i stedet for å kutte dem.

Hvis du kjører Nessie ved siden av andre applikasjoner på et delt Docker-nettverk, gi databasecontaineren et eget navn. Prosjektets egen Compose-tjeneste heter nessie-postgres og aldri postgres, fordi tjenestenavnet blir et DNS-alias på det delte nettverket, og en kollisjon gjør at postgres:5432 fordeles etter tur mellom to databaser.

Konfigurasjon

Kjøretidskonfigurasjonen er lagdelt: en nessie.config.json-fil montert skrivebeskyttet inn i API-et og worker-en, med miljøvariabler over den. Koblingen mellom de to er ConfigEnvMap i packages/config, som er den autoritative listen.

NESSIE_MODE velger driftsformen: local (standard, og utviklerveien), hosted eller selfHosted – som en egendrevet installasjon setter. Den slår av utviklerinnlogging og krever en CORS-liste.

Dette er innstillingene en selfHosted-installasjon ikke starter, eller ikke fungerer uten:

VariabelHvorfor
DATABASE_URL / NESSIE_DB_URLPostgres-tilkoblingsstrengen.
NESSIE_AUTH_SECRET32 byte heksadesimalt (openssl rand -hex 32). Signerer økter og bootstrap-tokener. Oppstart feiler uten den utenfor local-modus, og den må ha samme verdi på hver replika og på tvers av deployer, ellers dør alle økter ved hver utgivelse.
NESSIE_ENCRYPTION_KEY_RING, NESSIE_ENCRYPTION_ACTIVE_KEY_VERSIONEn JSON-nøkkelring og etiketten som velger aktiv rot, påkrevd utenfor local-modus. Dette er en egen rot fra signeringshemmeligheten – nøkkelringen krypterer hver varige hemmelighet Nessie lagrer. Bruk ikke den ene som den andre.
NESSIE_STORAGE_PROVIDERMå være s3. filesystem er standard og avvises i hosted- og selfHosted-modus, så en installasjon som ikke setter noe her, starter ikke i stedet for å skrive opplastinger til en disk ingen annen container kan lese.
NESSIE_CORS_ORIGINSAdmin-originen. Admin og API er separate origins, og API-et må tillate den originen det serverer.
NESSIE_API_PUBLIC_URL, NESSIE_ADMIN_PUBLIC_URLBrukes til å lage OAuth-omdirigerings-URI-er utenfor en HTTP-forespørsel. API-et kaster en feil ved forespørsel uten den første.
NESSIE_MODEL_PROVIDER, _BASE_URL, _API_KEYHvor inferensen går. Se under.

infrastructure/compose/.env.prod.example viser nøyaktig formen på alle, med de valgfrie blokkene – objektlagring, hemmelighetsvault, SSO og tilkoblet e-post – kommentert inn der de hører hjemme. Den fulle katalogen, inkludert alle valgfrie innstillinger, er docs/deployment/configuration.md.

Installere med Docker Compose

Kopier .env.prod.example til .env ved siden av docker-compose.prod.yml og fyll den ut. Start deretter databasen, bygg, migrer og start. Rekkefølgen betyr noe: migreringene og seed-ene kjøres mot en database som allerede er oppe, før noen tjeneste svarer.

COMPOSE="docker compose -f infrastructure/compose/docker-compose.prod.yml"

bash infrastructure/compose/ensure-encryption-key-ring.sh infrastructure/compose/.env
$COMPOSE up -d nessie-postgres
$COMPOSE build nessie-api nessie-admin nessie-web
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api prisma:migrate:deploy
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api seed:connectors
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api seed:apps
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api reconcile
$COMPOSE up -d

Produksjons-Dockerfilene kjører hver pakkes lint før den bygges, så en lint-feil er en byggefeil.

Reconcile-steget er ikke valgfritt

reconcile legger inn hver organisasjons standardregler for retningslinjer og fyller inn i etterkant tilgangene til beskyttede MCP-verktøy og Personal Assistant. API-et gjorde dette ved oppstart på hver replika; nå kobler det seg til, lytter og gjør ingenting annet. Uten dette steget har den første organisasjonen ingen retningslinjeregler, og hver agentbinding blir avvist. Steget er idempotent, så å kjøre det ved hver deploy koster ingenting – og en oppgradering du gjør manuelt, må også kjøre det.

Den første eierkontoen

En ny selfHosted-installasjon har ingen brukere, så API-et lager et engangs-bootstrap-token og logger en oppsett-URL. Tokenet ligger i Postgres og ikke i en prosess, så hver replika er enig om det.

docker compose -f infrastructure/compose/docker-compose.prod.yml logs nessie-api 2>&1 | grep bootstrap

Åpne https://<your-admin-host>/bootstrap?token=<token> og opprett eierkontoen. Tokenet utløper etter 15 minutter; start API-tjenesten på nytt for å lage et nytt.

Hvis du setter opp SSO, finnes det ikke noe bootstrap-steg i det hele tatt. Bootstrap-modus slås av i det øyeblikket en ekstern autentiseringsleverandør er aktivert – ellers ville den kapre innloggingsskjermen – og den første personen som logger inn via SSO, oppretter standardteamet og blir eier av det.

Konfigurere inferens

Chat er OpenAI-kompatibel. NESSIE_MODEL_BASE_URL er endepunktet, NESSIE_MODEL_API_KEY bearer-nøkkelen, og NESSIE_MODEL_PROVIDER navngir adapteren – Nessie kompilerer adaptere for openai, kimi og deepseek, og når alt annet gjennom den generiske OpenAI-kompatible koblingen. NESSIE_MODEL_NAME setter installasjonens standardmodell, som en enkelt agents egne modellvalg fortsatt går foran.

Embeddings rutes separat, fordi chat-leverandøren kanskje ikke tilbyr dem i det hele tatt – DeepSeek har for eksempel ikke noe embeddings-endepunkt. Hvert NESSIE_EMBEDDING_*-felt som ikke er satt, arver chat-leverandøren, så en installasjon som ikke setter noen av dem, lager embeddings via chat-endepunktet. Sett NESSIE_EMBEDDING_PROVIDER, NESSIE_EMBEDDING_MODEL og, på en proxy som ruter etter tjeneste, tjenestesegmentet, når chat-leverandøren ikke kan lage embeddings. Feil her gir stille feil i stedet for høylytte: hukommelsesgjenfinning og kunnskapsbasesøk faller tilbake til en leksikalsk kanal og fortsetter, og logger kb_search: query embedding failed underveis.

Nessies eget forbruksregnskap – tokenregnskapet per organisasjon og budsjettporten – påvirkes ikke av hvilket endepunkt du peker den mot, og fungerer likt enten signert attribusjon per kall er konfigurert eller ikke.

Logge inn

Nessie autentiserer personer via UnlikeOtherAI, som også administrerer organisasjons- og teamstrukturen. Admin-innloggingssiden viser én enkelt «Login / Register»-knapp.

Integrasjonen er en config-JWT-flyt, ikke standard OIDC: API-et serverer et signert RS256-konfigurasjonsdokument på GET /api/auth/sso/config og den tilhørende JWKS-en på GET /.well-known/jwks.json, begge på API-verten. Å sette det opp er en engangsrekkefølge: generer et RSA-2048-nøkkelpar og sett UOA_CONFIG_JWT_PRIVATE_KEY_B64, UOA_CONFIG_JWT_KID, UOA_DOMAIN, UOA_CONFIG_URL, UOA_JWKS_URL, UOA_REDIRECT_URL og UOA_CONTACT_EMAIL. Klikk på knappen én gang, som oppretter en integrasjonsforespørsel. Få den godkjent, som sender en engangslenke til kontaktadressen med klienthemmeligheten. Sett UOA_CLIENT_SECRET og start API-et på nytt. Hver kid må være unik per domene.

Bak et domene, med TLS

En installasjon serverer tre navn: den offentlige siden, admin og API-et. Admin- og API-originene er ikke utbytbare. Dockerfile.admin baker VITE_API_BASE_URL inn i pakken ved byggetid, så hver bygget admin-artefakt – inkludert et desktop-bygg som innebygger den – må bygges mot API-originen. Bygger du den mot admin sin egen origin, blir /api/auth/providers til admin-ens HTML-skall, og innloggingen står fast på «Loading providers...».

Produksjon avslutter TLS i Caddy, som henter sertifikater per vertsnavn over HTTP-01 og ikke trenger en DNS-leverandør-plugin for det. Pek proxyen mot admin- og web-containerne på port 80 og mot API-et på dets interne port.

Sett NESSIE_API_TRUSTED_PROXY_HOPS til antall proxyer foran API-et – 1 bak én reverse proxy. Standard er 0, som ignorerer X-Forwarded-For helt. Dette er én beslutning med to konsekvenser: den styrer også autentiseringens hastighetsgrenser, så for lav verdi gjør at alle klienter deler proxyens bøtte, og for høy verdi lar en klient forfalske sin egen adresse. Velg heller lavt, og mål.

Å servere hver organisasjon og hvert team på sitt eget subdomene er mulig, og det er av som standard. Det styres av NESSIE_TEAM_HOST_BASE_DOMAIN. Uten verdi rutes ikke tenantene etter vertsnavn i det hele tatt, og sertifikatutstedingsporten NESSIE_TLS_CHECK_KEY avviser alt så lenge den ikke er satt. Det er det riktige standardvalget for en installasjon som ikke bruker funksjonen.

Helsesjekker

EndepunktSpørsmål det besvarer
GET /api/healthLever denne prosessen? Feiler først når den har begynt å tømme seg.
GET /api/health/readyKan denne replikaen ta imot nye forespørsler? Dette er den du skal peke en load balancer mot.
GET /api/ops/healthHvordan har det det med installasjonen? En rapport for et menneske – worker-hjerteslag, kølengde, døde jobber – ikke en probe.

Ved SIGTERM tømmer API-et seg i stedet for å dø der det står. NESSIE_SHUTDOWN_TIMEOUT_MS setter en grense for tømmingen og er som standard 25 sekunder. Hold den under karenstiden orkestratoren gir containeren, ellers dreper kjøremiljøet prosessen først, og tømmingen gjør ingen nytte.

Oppgradere

En oppgradering er prisma migrate deploy mot den eksisterende databasen, deretter seed-ene, deretter reconcile. De samme fire kommandoene som ved første deploy.

Veien er testet for veien en egendrevet installasjon faktisk tar, ikke mot en ny database: CI gjenoppretter et øyeblikksbilde tatt tjue migreringer bak, migrerer det til gjeldende hode, validerer skjemaet og kjører en røykprøve mot kjernetabellene. Enhver utgivelse innenfor de siste tjue migreringene er en bevist oppgraderingskilde. Migreringsmapper er uforanderlige når de er committet, og et lint-steg feiler bygget hvis en blir omdøpt, renummerert, slettet eller endret, fordi alle fire ødelegger migrate deploy for en database som allerede har registrert den gamle raden.

Én mislykket migrering stopper alle deployer etter den. migrate deploy stopper ved den første feilen og avviser hver senere migrering med P3009, så installasjonen blir på den gamle utgivelsen til noen fjerner feilen manuelt. Prosjektets egen produksjon brukte en dag på å avvise hver deploy på denne måten. Å fjerne den betyr å bekrefte at den mislykkede migreringen faktisk ble rullet tilbake – ingen av objektene den oppretter skal finnes, og det den endrer skal ha sin opprinnelige form – og først da løse den som tilbakerullet. En migrering som delvis ble brukt, er ikke en kandidat.

Sikkerhetskopiering og gjenoppretting for den egendrevne Compose-installasjonen er ikke dokumentert i repositoriet, så denne siden beskriver ingen prosedyre for det.

Én maskin, eller en administrert sky

Den enkelt-vertede Docker Compose-veien ovenfor er den som er bevist: det er det prosjektets egen produksjon kjører, på én server, med databasen, objektlagringen, API-et, worker-en, admin og nettsiden som containere bak en delt reverse proxy.

Å skalere utover én maskin endrer tre ting, og alle tre håndheves i stedet for bare anbefales. Utenfor local-modus kjører Nessie API-et og worker-en som separate prosesser, og som flere kopier av hver. Derfor avvises enhver funksjon som forutsetter at én prosess eier maskinens disk: filbasert objektlagring (en oppstartsfeil), miljømaler for kjøremiljøer med docker-leverandøren (inaktive, og klargjøringen feiler høylytt), og de innebygde verktøyene file_read, file_write og file_glob (et mislykket verktøyresultat som agenten kan lese). Hver avvisning nevner innstillingen, modusen og hva du skal bruke i stedet.

For en administrert sky har repositoriet et Terraform-tre i infrastructure/terraform/ rettet mot Google Cloud: API-et som en Cloud Run-tjeneste med minst én instans – den holder en vedvarende Postgres-LISTEN-klient og kjører vedlikeholdssveiper, så å skalere den til null stopper sanntidsleveringen – worker-en som en Cloud Run worker pool, fordi den ikke binder noen port og en Service aldri ville blitt klar, en migreringsjobb som styrer hver utrulling, Cloud SQL for PostgreSQL 17, og en GCS-bøtte nådd gjennom den S3-kompatible backenden.

Den veien er skrevet, ikke gått. Repositoriet sier det rett ut, og det gjør denne siden også: det finnes ikke noe Google Cloud-prosjekt for den, ingenting i treet er planlagt eller satt opp mot et ekte prosjekt, multipart-opplastingsveien til GCS er ikke testet mot en ekte bøtte, worker pool-ressurstypen er ikke validert, og antallet trusted-proxy-hopp der er en plassholder som skal måles, ikke en måling. Admin og den offentlige nettsiden er ikke modellert der i det hele tatt. Behandle den som et utgangspunkt du verifiserer, ikke som en støttet installasjon.

Hvor en installasjons data ligger, hva programvaren holder og bevisst ikke holder, er en egen side: Laget i EU, og hvor dataene dine ligger.