Instalacija Nessieja
Pokrenite Nessie na infrastrukturi koju izaberete, od jedne mašine do upravljanog oblaka.
Šta vam treba prije početka
Nessie je pnpm monorepo sa Node servisima i dva statička paketa. Bez obzira na način pokretanja, prvo moraju postojati ova četiri elementa.
- PostgreSQL sa
pgvector. Nije opcionalno i ne može se zamijeniti — migracije izvršavajuCREATE EXTENSION vectori kreiraju kolonevector(1024). Produkcija koristipgvector/pgvector:pg17. - Node 22 i pnpm. Svaki Dockerfile u
infrastructure/docker/gradi se nanode:22-slim, a repozitorij u korijenskompackage.jsonfiksira verziju menadžera paketa (pnpm@10.22.0). - Krajnja tačka OpenAI-kompatibilnog modela i ključ za nju. Agenti i ugrađivanja (embeddings) prolaze kroz nju. Pogledajte „Konfigurisanje inferencije“ ispod.
- S3-kompatibilno objektno skladište, za svako postavljanje koje nije lokalno developersko. Otpremanje na lokalni disk odbija se van načina
local, a to odbijanje je greška pri pokretanju, a ne umanjeno pokretanje — pogledajte „Jedna mašina ili upravljani oblak“.
Docker i reverse proxy potrebni su za put kroz kontejnere opisan niže, a domen i TLS za sve što je dostupno s interneta.
Dimenzioniranje hardvera — minimalni procesor, memorija i disk za određeni broj ljudi — nije navedeno nigdje u repozitoriju, pa ni ova stranica to ne navodi.
Komponente i kako se uklapaju
| Komponenta | Šta je | Ulaz |
|---|---|---|
api/ | Fastify HTTP/WebSocket API. Svaki klijent komunicira s njim i ni s čim drugim. | Da |
worker/ | Orkestracija agenata i pozadinska izvršavanja. Provjerava red poslova; ne veže nijedan port. | Ne |
admin/ | Interfejs proizvoda — statički paket koji gradi Vite, a služi ga nginx. | Da |
web/ | Javna web stranica. Statičan, opcionalan i nije povezan s pokretanjem proizvoda. | Da |
| PostgreSQL | Baza podataka, red poslova i realtime sabirnica — sve tri. | Ne |
| Objektno skladište | Prilozi, avatari i datoteke baze znanja. S3-kompatibilno; u produkciji MinIO. | Ne |
gateway/ | Opcioni posrednik za push obavijesti preko APNs i FCM. Isključen je dok ga ne uključite namjerno. | Da |
API i worker su jedna slika. Dva paketa su čvrsto povezana, pa Dockerfile.app jednom izgradi cijeli tim, a worker kontejner prepisuje naredbu na node worker/dist/index.js. U načinu local uopće nema workera kao kontejnera: API pokreće worker ugrađen u vlastiti proces.
Nema Redisa. Red poslova i realtime transport zasnovani su na Postgresu, po odluci, a ne propustom — Google Cloud stablo iz istog razloga briše svoje Pub/Sub i Redis module.
Portovi
U lokalnom razvoju API je po zadanim postavkama na 5454, a admin na 5455. Radna kopija repozitorija može uzeti vlastiti par postavljanjem NESSIE_API_PORT i NESSIE_ADMIN_PORT, u okruženju ili u datoteci .env repozitorija; svaki alat u repozitoriju, uključujući browser test pakete, čita iste dvije vrijednosti. Izaberite par prije pokretanja i zadržite ga: premještanje pokrenutog servisa na drugi port ostavlja admin da razgovara s pogrešnim API-jem.
Produkcija je druga stvar, i ovo pravilo na nju ostaje nepromijenjeno. API kontejner sluša interno na 5554 (fiksirano pomoću NESSIE_API_PORT), a push posrednik na 5556, oba iza reverse proxyja.
Pokretanje na jednoj mašini, za razvoj
Repozitorij sadrži Compose datoteku samo s bazom podataka, što je sve što lokalni tok treba.
pnpm install
docker compose -f infrastructure/compose/docker-compose.yml up -d postgresTaj kontejner objavljuje Postgres na 55432, a korisničko ime, lozinka i baza se zovu nessie. Stavite connection string u .env u korijenu repozitorija — razvojna skripta API-ja ga čita — zatim jednom primijenite migracije i izgradite worker, jer u lokalnom načinu API učitava worker iz njegovog izgrađenog dist:
DATABASE_URL=postgresql://nessie:nessie@localhost:55432/nessie
pnpm --filter @nessie/api prisma:migrate:deploy
pnpm --filter @nessie/worker build
pnpm devpnpm dev pokreće API i admin paralelno, uz hot reload, na 5454 i 5455. Provjerite da je API odgovorio na GET /api/health.
Postgres i zahtjev za pgvector
Tri ekstenzije kreiraju same migracije — vector, pg_trgm i pgcrypto — pa uloga koja ih izvršava mora smjeti kreirati ekstenzije. Na upravljanom Postgresu to je prva stvar koju treba provjeriti.
Širina vektora dio je šeme, a ne postavka. thoughts.embedding, thought_recalls.query_embedding i knowledge_page_chunks.embedding su kolone vector(N), a N je navedeno jednom kao EMBEDDING_DIMENSIONS u packages/schemas/src/embedding.ts — trenutno 1024, izvorna širina modela za ugrađivanje koji produkcija koristi. Svaki zahtjev za ugrađivanje šalje tu širinu, pa pružatelj koji bi odgovorio drugom širinom pada glasno, umjesto da upisuje vektore koje baza odbija. Prelazak na model za ugrađivanje druge širine znači izmijeniti tu konstantu, napisati migraciju koja mijenja tip sve tri kolone i ponovo ugraditi sadržaj: vektori različitih širina ne mogu se pretvoriti, pa migracija njihove vrijednosti postavlja na null umjesto da ih skraćuje.
Ako Nessie pokrećete uz druge aplikacije na zajedničkoj Docker mreži, dajte kontejneru baze jedinstveno ime. Compose servis projekta zove se nessie-postgres, nikada postgres, jer ime servisa postaje DNS alias na zajedničkoj mreži, a sudar bi učinio da se postgres:5432 naizmjenično rješava između dvije baze.
Konfiguracija
Konfiguracija pri izvršavanju je slojevita: datoteka nessie.config.json montirana samo za čitanje u API i worker, a preko njega idu varijable okruženja. Preslikavanje između njih je ConfigEnvMap u packages/config, i to je mjerodavan spisak.
NESSIE_MODE bira oblik postavljanja: local (podrazumijevani i razvojni put), hosted ili selfHosted — što postavlja samostalno instalirana verzija. Ona isključuje razvojnu prijavu i zahtijeva listu dozvoljenih CORS origina.
To su postavke bez kojih se selfHosted postavljanje neće pokrenuti ili neće raditi:
| Varijabla | Zašto |
|---|---|
DATABASE_URL / NESSIE_DB_URL | Connection string za Postgres. |
NESSIE_AUTH_SECRET | 32 bajta u heksadecimalnom zapisu (openssl rand -hex 32). Potpisuje sesije i bootstrap tokene. Pokretanje pada bez nje van načina local, a mora biti ista vrijednost na svakoj replici i kroz sva postavljanja, inače se svaka sesija prekine pri svakom izdanju. |
NESSIE_ENCRYPTION_KEY_RING, NESSIE_ENCRYPTION_ACTIVE_KEY_VERSION | JSON prsten ključeva i oznaka koja bira aktivni root, obavezni van načina local. Ovo je poseban root u odnosu na potpisni tajni ključ — prsten šifruje svaku trajnu tajnu koju Nessie čuva. Nemojte koristiti jedan kao drugi. |
NESSIE_STORAGE_PROVIDER | Mora biti s3. filesystem je podrazumijevani, a odbija se u načinima hosted i selfHosted, pa postavljanje koje ovdje ništa ne postavi neće ni startovati, umjesto da upload piše na disk koji nijedan drugi kontejner ne može čitati. |
NESSIE_CORS_ORIGINS | Origin admina. Admin i API su zasebni origini, a API mora na listi dozvoljenih imati onaj koji servira. |
NESSIE_API_PUBLIC_URL, NESSIE_ADMIN_PUBLIC_URL | Koriste se za generisanje OAuth redirect URI-ja izvan HTTP zahtjeva. API baca grešku u trenutku zahtjeva ako nije postavljen prvi od njih. |
NESSIE_MODEL_PROVIDER, _BASE_URL, _API_KEY | Gdje ide inferencija. Pogledajte niže. |
infrastructure/compose/.env.prod.example ima tačan oblik svih njih, s opcionalnim blokovima — objektnim skladištem, trezorom tajni, SSO-om, povezanom poštom — zakomentarisanim na mjestu. Potpuni katalog, uključujući svaku opcionalnu postavku, je docs/deployment/configuration.md.
Postavljanje pomoću Docker Composea
Kopirajte .env.prod.example u .env pored docker-compose.prod.yml i popunite ga, zatim pokrenite bazu, izgradite, migrirajte i pokrenite servise. Redoslijed je bitan: migracije i početni podaci izvršavaju se nad bazom koja je već pokrenuta, prije nego ijedan servis počne da služi.
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 -dProdukcijski Dockerfileovi pokreću lint svakog paketa prije gradnje, pa je greška u lintu ujedno i greška pri gradnji.
Korak reconcile nije opcionalan
reconcile postavlja podrazumijevana pravila politike svake organizacije i naknadno dodjeljuje zaštićene MCP i Personal Assistant dodjele alata. API je to nekada radio pri pokretanju na svakoj replici; sada se samo poveže, počne slušati i ništa više ne radi, pa bez ovog koraka prva organizacija nema pravila politike i svako vezivanje agenta biva odbijeno. Idempotentan je, pa je pokretanje na svakom postavljanju besplatno — a nadogradnja primijenjena ručno mora ga također pokrenuti.
Prvi vlasnički nalog
Svježe selfHosted postavljanje nema korisnike, pa API izdaje jednokratni bootstrap token i zapisuje URL za podešavanje. Token živi u Postgresu, a ne u procesu, pa se sve replike slažu oko njega.
docker compose -f infrastructure/compose/docker-compose.prod.yml logs nessie-api 2>&1 | grep bootstrapOtvorite https://<your-admin-host>/bootstrap?token=<token> i kreirajte vlasnički nalog. Token ističe nakon 15 minuta; ponovo pokrenite API servis da biste izdali novi.
Ako konfigurišete SSO, uopće nema koraka bootstrapa. Bootstrap način se potiskuje čim se uključi vanjski pružatelj identiteta — inače bi preuzeo ekran za prijavu — a prva osoba koja se prijavi preko SSO-a pokreće podrazumijevani tim i postaje njegov vlasnik.
Konfigurisanje inferencije
Chat je OpenAI-kompatibilan. NESSIE_MODEL_BASE_URL je krajnja tačka, NESSIE_MODEL_API_KEY bearer ključ, a NESSIE_MODEL_PROVIDER imenuje adapter — Nessie ima ugrađene adaptere za openai, kimi i deepseek, a sve ostalo ide kroz generički OpenAI-kompatibilni konektor. NESSIE_MODEL_NAME postavlja podrazumijevani model postavljanja, koji i dalje nadjačava izbor modela pojedinačnog agenta.
Ugrađivanja se usmjeravaju zasebno, jer chat pružatelj možda uopće ne nudi ugrađivanja — DeepSeek, na primjer, nema krajnju tačku za ugrađivanja. Svako nepostavljeno polje NESSIE_EMBEDDING_* nasljeđuje chat pružatelja, pa postavljanje koje nijedno ne postavlja ugrađuje preko chat krajnje tačke. Postavite NESSIE_EMBEDDING_PROVIDER, NESSIE_EMBEDDING_MODEL i, na proxyju koji usmjerava po servisu, segment servisa, kada chat pružatelj ne može ugrađivati. Pogrešna postavka ne pada glasno, nego tiho: pamćenje i pretraga baze znanja prebacuju se na leksički kanal i nastavljaju rad, uz zapis kb_search: query embedding failed.
Nessiejevo obračunavanje potrošnje — dnevnik tokena po organizaciji i kontrola budžeta — nije pogođeno time na koju krajnju tačku usmjeravate i radi jednako bez obzira na to je li konfigurisano potpisano pripisivanje po pozivu.
Prijava
Nessie autentifikuje ljude preko UnlikeOtherAI, koji upravlja i strukturom organizacija i timova. Stranica za prijavu u adminu prikazuje jedno dugme „Login / Register“.
Integracija je config-JWT tok, a ne standardni OIDC: API servira potpisani RS256 konfiguracioni dokument na GET /api/auth/sso/config i odgovarajući JWKS na GET /.well-known/jwks.json, oba na API hostu. Postavljanje je jednokratni niz — generišite RSA-2048 par ključeva i postavite UOA_CONFIG_JWT_PRIVATE_KEY_B64, UOA_CONFIG_JWT_KID, UOA_DOMAIN, UOA_CONFIG_URL, UOA_JWKS_URL, UOA_REDIRECT_URL i UOA_CONTACT_EMAIL; kliknite dugme jednom, što podiže zahtjev za integraciju; sačekajte da bude odobren, što na kontakt adresu šalje jednokratni link s klijentskom tajnom; postavite UOA_CLIENT_SECRET i ponovo pokrenite API. kid mora biti jedinstven po domenu.
Postavljanje iza domena, uz TLS
Postavljanje služi tri imena: javna web stranica, admin i API. Origini admina i API-ja nisu zamjenjivi. Dockerfile.admin ugrađuje VITE_API_BASE_URL u paket u trenutku gradnje, pa svaki izgrađeni admin artefakt — uključujući desktop verziju koja ga ugrađuje — mora biti izgrađen za API origin. Ako ga izgradite za vlastiti origin admina, /api/auth/providers se razrješava u HTML ljusku admina, pa prijava ostane zaglavljena na „Loading providers...“.
Produkcija završava TLS na Caddyju, koji dobija certifikate po imenu hosta preko HTTP-01 i za to ne treba DNS-provider plugin. Usmjerite proxy na admin i web kontejnere na portu 80, a na API na njegov interni port.
Postavite NESSIE_API_TRUSTED_PROXY_HOPS na broj proxyja ispred API-ja — 1 iza jednog reverse proxyja. Podrazumijevana vrijednost je 0, što u potpunosti ignoriše X-Forwarded-For. Ovo je jedna odluka s dvije posljedice: njome se određuju i ograničenja broja pokušaja prijave, pa ako je premala, svaki klijent dijeli kantu proxyja, a ako je prevelika, klijent može krivotvoriti vlastitu adresu. Grešite na nižu stranu i izmjerite.
Služenje svake organizacije i tima na vlastitom poddomenu je moguće, a isključeno je podrazumijevano. Upravlja se s NESSIE_TEAM_HOST_BASE_DOMAIN: ako nije postavljeno, organizacije se uopće ne usmjeravaju po hostu, a kapija za izdavanje certifikata NESSIE_TLS_CHECK_KEY odbija sve dok nije postavljena — što je ispravna podrazumijevana vrijednost za postavljanje koje ne koristi tu funkciju.
Provjere zdravlja
| Krajnja tačka | Pitanje na koje odgovara |
|---|---|
GET /api/health | Je li ovaj proces živ? Pada tek kada je počeo da se prazni. |
GET /api/health/ready | Smije li ova replika primati nove zahtjeve? Na nju treba usmjeriti load balancer. |
GET /api/ops/health | Kako ide postavljanje? Izvještaj za osobu — srčani signali workera, dubina reda, mrtvi poslovi — a ne probe. |
Na SIGTERM API se prazni, umjesto da odmah umre. NESSIE_SHUTDOWN_TIMEOUT_MS ograničava to pražnjenje i podrazumijevano iznosi 25 sekundi; držite ga ispod kakvog god grace perioda vaš orkestrator daje kontejneru, inače runtime prvo ubije proces i pražnjenje ništa ne donosi.
Nadogradnja
Nadogradnja je prisma migrate deploy nad postojećom bazom, zatim početni podaci, pa reconcile. Iste četiri naredbe kao i pri prvom postavljanju.
Put je testiran za rutu kojom samostalni korisnik zaista ide, a ne nad svježom bazom: CI vraća snimak uzet dvadeset migracija unazad, migrira ga na trenutni head, provjerava šemu i pokreće smoke provjeru nad osnovnim tabelama. Svako izdanje unutar tog zadnjeg prozora dokazan je izvor nadogradnje. Direktoriji migracija su nepromjenjivi nakon commita, a lint korak ruši build ako se jedan preimenuje, promijeni mu se redni broj, obriše ili izmijeni, jer sve te radnje kvare migrate deploy za bazu koja je već zabilježila stari red.
Jedna neuspjela migracija blokira svako postavljanje poslije nje. migrate deploy staje na prvom neuspjehu i odbija svaku kasniju migraciju s P3009, pa instalacija ostaje na starom izdanju dok je neko ručno ne očisti. Produkcijska instanca samog projekta je cijeli dan odbijala svako postavljanje na ovaj način. Čišćenje jedne znači potvrditi da je neuspjela migracija zaista poništena — ništa što je ona kreirala ne bi smjelo postojati, a sve što je mijenjala mora biti u prvobitnom obliku — pa tek onda označiti je kao poništenu. Migracija koja je djelimično primijenjena nije kandidat.
Sigurnosna kopija i vraćanje za samostalno postavljanje putem Docker Composea nisu dokumentovani u repozitoriju, pa ova stranica ne opisuje postupak za to.
Jedna mašina ili upravljani oblak
Postavljanje na jednom hostu s Docker Composeom, opisano iznad, jedino je provjereno: na njemu radi produkcija projekta, na jednom serveru, s bazom, objektnim skladištem, API-jem, workerom, adminom i web stranicom kao kontejnerima iza zajedničkog reverse proxyja.
Skaliranje preko jedne mašine mijenja tri stvari, i sve su nametnute, a ne preporučene. Van načina local, Nessie pokreće API i worker kao zasebne procese i kao više kopija svakog, pa se svaka mogućnost koja pretpostavlja da jedan proces posjeduje disk mašine odbija: datotečni sistem objektnog skladišta (greška pri pokretanju), šabloni izvršnog okruženja s docker pružateljem (bez efekta, a provizija glasno pada) i ugrađeni alati file_read, file_write i file_glob (neuspjeli rezultat alata koji agent može pročitati). Svako odbijanje imenuje postavku, način i to šta koristiti umjesto toga.
Za upravljani oblak repozitorij sadrži Terraform stablo u infrastructure/terraform/ za Google Cloud: API kao Cloud Run servis s najmanje jednom instancom — drži trajni Postgres LISTEN klijent i pokreće sweepove održavanja, pa skaliranje na nulu zaustavlja realtime isporuku — worker kao Cloud Run worker pool, jer ne veže port i Service nikada ne bi postao spreman; migrate job koji mora proći prije svakog izdanja; Cloud SQL za PostgreSQL 17 i GCS bucket kojem se pristupa preko S3-kompatibilnog backenda.
Taj put je napisan, ali nije isproban. Repozitorij to otvoreno kaže, a i ova stranica: za njega ne postoji Google Cloud projekat, ništa u stablu nije planirano niti primijenjeno nad stvarnim projektom, multipart upload na GCS nije testiran nad stvarnim bucketom, tip resursa worker pool još nije validiran, a broj trusted-proxy hopova u njemu je privremena vrijednost koju treba izmjeriti, a ne izmjereni podatak. Admin i javna web stranica tamo uopće nisu modelovani. Tretirajte to kao polaznu tačku koju sami provjeravate, a ne kao podržano postavljanje.
Gdje podaci postavljanja žive, šta softver drži, a šta namjerno ne drži, posebna je stranica: Napravljeno u EU i gdje žive vaši podaci.