Kjør en headless server
Kjør cc_server på en maskin som står på hele tiden, og koble deg deretter til
den fra skrivebordet, en nettleser eller telefonen. Serveren er en native
binærfil i ren Dart — uten Flutter-motor — så den kjører headless på macOS,
Linux og Windows. Den eier databasen, kjører agentene og gjør hvert eneste
eksterne API-kall; klientene gjengir bare.
Kjør i Docker (forhåndsbygde imager)
Seksjon med tittelen «Kjør i Docker (forhåndsbygde imager)»Hver utgivelse publiserer en selvhostet stakk med fire GHCR-imager — backend-en,
de to statiske tynne klientene og det valgfrie paringsreléet — pluss et eget
cc-server-demo-image for den offentlige demoverten. En selvhostet installasjon
trenger ingen utsjekking av kildekoden. Fest en versjonstagg
(ghcr.io/samuelalev/<image>:v0.0.1-rc.1) eller følg latest.
| Image | Hva det er | Publiserer |
|---|---|---|
ghcr.io/samuelalev/cc-server |
Backend-en: database, agenter, MCP, webhooker | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Nettklienten (statisk nginx) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
Telefonfølgeappen (PWA, statisk nginx) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
WebRTC-paringsreléet (valgfritt) | -p 8788:8788 |
Hele stakken som en compose-fil:
services: server: image: ghcr.io/samuelalev/cc-server:latest ports: ["9030:9030"] volumes: ["cc_data:/data"] restart: unless-stopped web: image: ghcr.io/samuelalev/cc-webapp:latest ports: ["8080:8080"] restart: unless-stopped remote: image: ghcr.io/samuelalev/cc-remote:latest ports: ["8081:8080"] restart: unless-stopped signaling: image: ghcr.io/samuelalev/cc-signaling-server:latest ports: ["8788:8788"] restart: unless-stopped
volumes: cc_data:Noen ting det er verdt å vite før du eksponerer noe av dette utenfor loopback:
-
cc-server-imaget leveres medCC_SERVER_INSECURE=1(det må binde0.0.0.0for å ta imot trafikk på publiserte porter), noe som bare er trygt bak en TLS-avsluttende omvendt proxy — Caddy, Traefik, nginx eller en Cloudflare Tunnel — på et klarert nettverk. Vil du avslutte TLS i prosessen i stedet, monterer du et sertifikat og setterCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(og fjerner deretterCC_SERVER_INSECURE). Alt kan overstyres meddocker run -e …ellerenvironment:-blokken i compose. -
/dataer den eneste tilstanden. SQLite-databasene, hemmelighetene til parede enheter, nedlastede modeller og møtelyd ligger alle i volumet — sikkerhetskopier det, og containeren blir engangs. -
Par en klient fra inne i imaget før den første tilkoblingen; dette er container-ekvivalenten av trinn 3:
Terminalvindu docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
De to klientimagene er statiske nginx-verter — ingenting å konfigurere ved kjøring; hver klients tilkoblingsskjema tar imot server-URL-en, enhets-id-en og paringsnøkkelen din. Relémegleren trenger på samme måte bare porten sin (
SIGNALING_HOST/SIGNALING_PORTkan overstyres); den er tilstandsløs, oppbevarer ingen hemmeligheter og er en reserve — en telefon bruker loopback, LAN, tailnet eller en direktewss://-vei når en slik er tilgjengelig, og faller bare tilbake til reléet når ingen er det. Hopp over den hvis klientene dine alltid når serveren direkte.
Resten av denne veiledningen bygger serveren fra kildekoden; flaggene og oppførselen den dekker, er de samme som imagets miljøvariabler styrer.
Forutsetninger
Seksjon med tittelen «Forutsetninger»- Dart SDK. Dette repoet fester SDK-en sin med fvm, så sett
fvmforan hver kommando. - Dette repoet sjekket ut lokalt.
- Det native verktøysettet klargjøringsskriptet trenger — Rust/
cargo, plussmeson,ninja,pkg-config,gitog en C++-kompilator. Hvert byggeskript navngir det det ikke finner, og hvordan det installeres. - En vert som kan nås: loopback for lokal bruk, eller en LAN-/offentlig adresse med TLS for eksterne klienter.
Trinn 1: Klargjør de native bibliotekene
Seksjon med tittelen «Trinn 1: Klargjør de native bibliotekene»De native bibliotekene er påkrevd — det finnes ingen redusert modus. Bygg dem fra repoets rot før alt annet:
scripts/natives/build_natives.shDette bygger rift, fff, tree-sitter pluss grammatikkene, aec, lame,
ccpty, cc_watcher, cc_inference og SAML-native-biblioteket inn i
build/natives/. Byggkroken til cc_server sender videre det som er klargjort
der, inn i bunten, så hvis du hopper over dette trinnet, feiler bygget enten
helt, eller — med nødutgangen nedenfor — gir en binærfil der
forhåndssjekken ved oppstart nekter å starte og navngir det manglende
biblioteket.
Trinn 2: Bygg binærfilen
Seksjon med tittelen «Trinn 2: Bygg binærfilen»cd apps/cc_serverfvm dart build cliBunten leveres med libsqlite3 og de klargjorte native bibliotekene ved siden av
binærfilen — ingen system-SQLite og ingen Flutter-motor trengs. Den kjørbare
filen lander på ./build/cli/<os_arch>/bundle/bin/cc_server.
Trinn 3: Par en klient før første oppstart
Seksjon med tittelen «Trinn 3: Par en klient før første oppstart»En fersk datamappe har ingen paret enhet og ingen forhåndsdelt nøkkel, så en
klients forespørsel om paringsnøkkel kan ennå ikke besvares. Utsted én med
underkommandoen pair. Den skriver global.db og secrets.json direkte; en
server som allerede betjener den datamappen, plukker opp den nye enheten uten
omstart:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Den skriver ut tre verdier du limer inn i en klients tilkoblingsskjema:
Connect a thin client (paste into its connect form): Server ws://localhost:9030/rpc Device id web-client Pairing key <a freshly generated key>Nyttige flagg: --device (standard web-client; id-en velger også
enhetskategorien — desktop, ios, android, alt annet er en nettklient),
--label (standard er plattformnavnet pluss vertsnavnet til denne maskinen),
--host (verten som skrives ut i URL-en, siden loopback ikke kan nås fra en
annen maskin) og --client-url. Kjører du pair på nytt, roteres nøkkelen til
den enheten, og de aktive øktene dens avsluttes. Paring oppretter aldri et
arbeidsområde: onboardingen til klienten som kobler til, navngir og oppretter det
første.
Med --client-url skriver den også ut en QR-kode som kan skannes fra
terminalen, og som åpner nettklienten ferdig utfylt:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030 \ --bind any --host 192.168.1.42 --client-url https://app.usectrl.devEn legitimasjon utstedt av cc_server pair har ingen utløpstid; en som er
utstedt i appen, utløper alltid etter 30 dager. Tilbakekall en enhet utstedt fra
CLI-et fra Innstillinger → Deg → Dine enheter når du er ferdig med den.
Trinn 4: Start serveren
Seksjon med tittelen «Trinn 4: Start serveren»På loopback — standarden, og alt du trenger for en klient på samme maskin:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030For å nå den fra en annen maskin, bind alle grensesnitt. En binding utenfor
loopback uten TLS blir avvist ved oppstart (Refusing to bind non-loopback address … without TLS), så oppgi et sertifikat:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --tls-cert /path/fullchain.pem --tls-key /path/privkey.pem \ --public-url wss://server.example:9030/rpcEller avslutt TLS i en omvendt proxy på et klarert privat nettverk og velg en klartekstbinding bak den:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpc--insecure ignoreres når både --tls-cert og --tls-key er satt — TLS vinner
alltid. Serveren annonserer klarteksttilstanden som insecure: true i
GET /healthz, og klienter merker en slik tilkobling som usikker.
Serveren kjører til SIGINT/SIGTERM, og avsluttes deretter ryddig.
Trinn 5: Koble til en klient
Seksjon med tittelen «Trinn 5: Koble til en klient»Pek en klient mot server-URL-en og paringsnøkkelen fra trinn 3:
- Skrivebordsappen: på førstegangsskjermen (Hvordan skal Control Center kjøre?) fyller du ut tilkoblingsfeltene i stedet for Kjør i denne appen, eller legger til serveren senere under Innstillinger → Server → Tilkobling og status. Se Koble til en ekstern server.
- Nettklient: åpne app.usectrl.dev (eller din egen kopi av nettbygget) og skriv inn server-URL-en, enhets-id-en og paringsnøkkelen.
- Telefon: par Remote-appen fra en klient som kjører — se Koble til en enhet.
Trinn 6: Koble til en Google Calendar (valgfritt)
Seksjon med tittelen «Trinn 6: Koble til en Google Calendar (valgfritt)»For å synkronisere kalenderen til et arbeidsområde uten noe grafisk grensesnitt, bruk enhetskodeflyten:
GOOGLE_OAUTH_CLIENT_ID=<id> GOOGLE_OAUTH_CLIENT_SECRET=<secret> \ ./build/cli/<os_arch>/bundle/bin/cc_server calendar connect \ --data-dir ./data --workspace <workspace-id>Den skriver ut en kode og en URL du godkjenner på en annen enhet, lagrer
oppdateringstokenet på serversiden og avslutter. Et bygg fra kildekoden leveres
uten Google-klient, så miljøvariablene for id og hemmelighet er påkrevd — det
finnes ikke noe --google-client-id-flagg. Se Koble til en Google Calendar.
Konfigurasjon
Seksjon med tittelen «Konfigurasjon»Flaggene som er brukt ovenfor, er de en første oppsett trenger. Den komplette
flaten — 23 flagg- og miljøvariabelpar, de fire underkommandoene og oppsettet av
datamappen — står i CLI-referansen for cc_server.
De fire du mest sannsynlig trenger:
| Flagg | Standard | Betydning |
|---|---|---|
--data-dir |
operativsystemets appdatamappe per bruker | Databaser, hemmeligheter, modeller og hurtiglagret media |
--port |
9030 |
TCP-port (0 = efemær) |
--bind |
loopback |
loopback, eller any for alle grensesnitt (krever TLS eller --insecure) |
--public-url |
utledet fra bindingen | RPC-URL-en som annonseres til parede klienter. Sett denne eksplisitt bak en proxy, NAT eller tunnel |
Standard datamappe er ~/Library/Application Support/control-center på macOS,
%APPDATA%\control-center på Windows og $XDG_DATA_HOME/control-center (ellers
~/.local/share/control-center) andre steder. En .cc_server relativ til
arbeidsmappen brukes bare når verken hjemmemappen eller appdatamappen lar seg
finne.
Hva serveren betjener
Seksjon med tittelen «Hva serveren betjener»cc_server er hele produktflaten, ikke et utvalg: RPC-datastien og
abonnementene for repoet, MCP-verktøyendepunktet på POST /mcp og GET /sse på
samme port, innkommende webhooker, medie- og skriftproxyene, tilbakekallinger for
enkel pålogging, flåte-leaseprotokollen, RSS-henting på serversiden hvert
30. minutt og vektorsøk (sqlite_vector-utvidelsen registreres som en
prosessglobal auto-utvidelse og faller ned til fulltekstsøk bare der utvidelsen
ikke er tilgjengelig).
Dispatcheren er tilstandsløs: det finnes ingen arbeidsområdebinding per økt.
Hvert arbeidsområdespesifikt kall bærer sin egen workspace_id, og tilgang
avgjøres av medlemskapet og rollen den som kaller har i arbeidsområdet — ikke av
å holde en paringsnøkkel.
To ting du bør vite før du eksponerer porten utenfor loopback:
- MCP svikter lukket utenfor verten. En MCP-flate uten token svarer bare på loopback. Å binde
anyutvider den ikke — en forespørsel utenfra avvises med «MCP requires a bearer token to answer non-loopback clients» til du konfigurerer ett (mcp.setToken, eller Innstillinger → Server → MCP-servere). GET /healthzer uautentisert med vilje, med jokertegn i CORS, og publiserer serverens id, navn, identitetsfingeravtrykk og byggeversjon. Klienter trenger fingeravtrykket for å feste serveren, så dette er med vilje — men det betyr at enhvercc_serversom kan nås, avslører så mye til hvem som helst som spør.