Kör en headless-server
Kör cc_server på en maskin som står på, och anslut sedan till den från
skrivbordet, en webbläsare eller telefonen. Servern är en nativ binär i ren Dart
– ingen Flutter-motor – så den kör headless på macOS, Linux och Windows. Den
äger databasen, kör agenterna och gör varje externt API-anrop; klienterna
renderar bara.
Kör i Docker (färdigbyggda avbildningar)
Avsnitt med rubriken “Kör i Docker (färdigbyggda avbildningar)”Varje release publicerar en egenhostad stack med fyra GHCR-avbildningar –
backend, de två statiska tunna klienterna och det valfria parkopplingsreläet –
plus en separat cc-server-demo-avbildning för den publika demovärden. En
egenhostad installation kräver ingen källkodsutcheckning. Lås en versionstagg
(ghcr.io/samuelalev/<image>:v0.0.1-rc.1) eller följ latest.
| Avbildning | Vad den är | Publicerar |
|---|---|---|
ghcr.io/samuelalev/cc-server |
Backend: databas, agenter, MCP, webhooks | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Webbklienten (statisk nginx) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
Telefonkompanjonen, en PWA (statisk nginx) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
WebRTC-parkopplingsreläet (valfritt) | -p 8788:8788 |
Hela stacken 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:Saker som är värda att veta innan du exponerar något av detta utanför loopback:
-
cc-server-avbildningen levereras medCC_SERVER_INSECURE=1(den måste binda0.0.0.0för att ta emot trafik på publicerade portar), vilket bara är säkert bakom en TLS-avslutande omvänd proxy – Caddy, Traefik, nginx eller en Cloudflare-tunnel – i ett betrott nätverk. För att i stället avsluta TLS i processen monterar du ett certifikat och sätterCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(och tar sedan bortCC_SERVER_INSECURE). Allt kan skrivas över meddocker run -e …eller compose-blocketsenvironment:. -
/dataär det enda tillståndet. SQLite-databaserna, hemligheterna för parkopplade enheter, nedladdade modeller och mötesljud ligger allt i volymen – säkerhetskopiera den och containern kan slängas. -
Parkoppla en klient inifrån avbildningen före den första anslutningen, containerns motsvarighet till steg 3:
Terminalfönster docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
De två klientavbildningarna är statiska nginx-värdar – inget att konfigurera vid körning; varje klients anslutningsformulär tar serverns URL, enhets-ID:t och parkopplingsnyckeln. Signaleringsreläet behöver på samma sätt bara sin port (
SIGNALING_HOST/SIGNALING_PORTkan skrivas över); det är tillståndslöst, håller inga hemligheter och är en reservväg – en telefon använder loopback, LAN, tailnet eller en direktwss://-väg när en sådan är nåbar, och faller bara tillbaka på reläet när ingen är det. Hoppa över det om dina klienter alltid når servern direkt.
Resten av den här guiden bygger servern från källkod; flaggorna och beteendet den tar upp är desamma som avbildningens miljövariabler matar in i.
Förutsättningar
Avsnitt med rubriken “Förutsättningar”- Dart SDK. Det här repot låser sin SDK med fvm, så prefixa varje kommando med
fvm. - Det här repot utcheckat.
- Den nativa verktygskedja som förberedelseskriptet behöver – Rust/
cargo, plusmeson,ninja,pkg-config,gitoch en C++-kompilator. Varje byggskript namnger det det inte hittar och hur du installerar det. - En nåbar värd: loopback för lokal användning, eller en LAN-/publik adress med TLS för fjärrklienter.
Steg 1: Förbered de nativa biblioteken
Avsnitt med rubriken “Steg 1: Förbered de nativa biblioteken”Nativen är obligatoriska – det finns inget degraderat läge. Bygg dem från repots rot innan något annat:
scripts/natives/build_natives.shDetta bygger rift, fff, tree-sitter plus dess grammatiker, aec, lame,
ccpty, cc_watcher, cc_inference och SAML-nativen till
build/natives/. Bygg-hooken för cc_server skickar vidare allt som förbereds
där till bundlen, så att hoppa över det här steget antingen får bygget att
misslyckas direkt eller – med nödutgången nedan – ger en binär vars förkontroll
vid start vägrar starta och namnger det saknade biblioteket.
Steg 2: Bygg binären
Avsnitt med rubriken “Steg 2: Bygg binären”cd apps/cc_serverfvm dart build cliBundlen innehåller libsqlite3 och de förberedda nativen tillsammans med
binären – ingen system-SQLite och ingen Flutter-motor behövs. Den körbara filen
hamnar i ./build/cli/<os_arch>/bundle/bin/cc_server.
Steg 3: Parkoppla en klient före första starten
Avsnitt med rubriken “Steg 3: Parkoppla en klient före första starten”En ny datakatalog har ingen parkopplad enhet och ingen i förväg delad nyckel, så
en klients uppmaning om parkopplingsnyckel kan ännu inte besvaras. Skapa en med
underkommandot pair. Kommandot skriver global.db och secrets.json direkt;
en server som redan betjänar den datakatalogen plockar upp den nya enheten utan
omstart:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Det skriver ut tre värden att klistra in i en klients anslutningsformulär:
Connect a thin client (paste into its connect form): Server ws://localhost:9030/rpc Device id web-client Pairing key <a freshly generated key>Användbara flaggor: --device (standard web-client; ID:t väljer också
enhetsnivån – desktop, ios, android, allt annat är en webbklient),
--label (standard är plattformsnamnet plus den här maskinens värdnamn),
--host (värden som skrivs ut i URL:en, eftersom loopback inte är nåbar från en
annan maskin) och --client-url. Att köra pair igen roterar den enhetens
nyckel och släpper dess live-sessioner. Parkoppling skapar aldrig någon
arbetsyta: den anslutande klientens onboarding namnger och skapar den första.
Med --client-url skriver det också ut en QR-kod som går att skanna i
terminalen och som öppnar webbklienten redan ifylld:
./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 autentiseringsuppgift som skapats av cc_server pair har ingen utgång; en
som skapats i appen löper alltid ut efter 30 dagar. Återkalla en enhet som
skapats i CLI:t från Inställningar → Du → Dina enheter när du är klar med
den.
Steg 4: Starta servern
Avsnitt med rubriken “Steg 4: Starta servern”På loopback – standardvärdet och allt du behöver för en klient på samma maskin:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030För att nå den från en annan maskin binder du alla gränssnitt. En bindning
utanför loopback utan TLS avvisas vid start (Refusing to bind non-loopback address … without TLS), så ange ett certifikat:
./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 avsluta TLS i en omvänd proxy i ett betrott privat nätverk och välj en klartextbindning bakom den:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpc--insecure ignoreras när både --tls-cert och --tls-key är satta – TLS
vinner alltid. Servern annonserar klartexttillståndet som insecure: true i
GET /healthz, och klienter märker en sådan anslutning som osäker.
Servern kör tills den får SIGINT/SIGTERM och stängs sedan av på ett rent
sätt.
Steg 5: Anslut en klient
Avsnitt med rubriken “Steg 5: Anslut en klient”Rikta en klient mot serverns URL och parkopplingsnyckeln från steg 3:
- Skrivbordsappen: på förstagångsskärmen (Hur ska Control Center köras?) fyller du i anslutningsfälten i stället för Kör i den här appen, eller lägger till servern senare under Inställningar → Server → Anslutning och status. Se Anslut till en fjärrserver.
- Webbklient: öppna app.usectrl.dev (eller din egen kopia av webbbygget) och ange serverns URL, enhets-ID och parkopplingsnyckeln.
- Telefon: parkoppla Remote-appen från en körande klient – se Para en enhet.
Steg 6: Anslut en Google Calendar (valfritt)
Avsnitt med rubriken “Steg 6: Anslut en Google Calendar (valfritt)”För att synkronisera en arbetsytas kalender utan något GUI använder du enhetskodsflödet:
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>Kommandot skriver ut en kod och en URL att godkänna på en annan enhet, lagrar
refresh-token på serversidan och avslutar. Ett källkodsbygge levereras utan
någon Google-klient, så miljövariablerna för ID och hemlighet krävs – det finns
ingen flagga --google-client-id. Se
Anslut en Google Calendar.
Konfiguration
Avsnitt med rubriken “Konfiguration”Flaggorna ovan är de som en första installation behöver. Hela ytan – 23 par av
flaggor och miljövariabler, de fyra underkommandona och datakatalogens layout –
finns i cc_server-CLI-referensen.
De fyra du med största sannolikhet behöver:
| Flagga | Standard | Betydelse |
|---|---|---|
--data-dir |
operativsystemets användarspecifika appdatakatalog | Databaser, hemligheter, modeller och cachelagrade media |
--port |
9030 |
TCP-port (0 = tillfällig) |
--bind |
loopback |
loopback, eller any för alla gränssnitt (kräver TLS eller --insecure) |
--public-url |
härleds från bindningen | RPC-URL:en som annonseras till parkopplade klienter. Sätt den uttryckligen bakom en proxy, NAT eller tunnel |
Standarddatakatalogen är ~/Library/Application Support/control-center på macOS,
%APPDATA%\control-center på Windows och $XDG_DATA_HOME/control-center (annars
~/.local/share/control-center) på andra plattformar. En .cc_server relativ
till cwd används bara när ingen hem- eller appdatakatalog kan lösas upp.
Vad servern betjänar
Avsnitt med rubriken “Vad servern betjänar”cc_server är hela produktytan, inte en delmängd: repo-RPC-datavägen och
prenumerationerna, MCP-verktygsändpunkten på POST /mcp och GET /sse på samma
port, inkommande webhooks, proxyerna för media och teckensnitt, återanrop för
enkel inloggning, fleet-lease-protokollet, RSS-hämtning på serversidan enligt
ett 30-minutersschema samt vektorsökning (sqlite_vector-tillägget registreras
som ett processglobalt automatiskt tillägg och degraderar till fulltextsökning
bara där tillägget inte är tillgängligt).
Dispatchern är tillståndslös: det finns ingen arbetsytebindning per session.
Varje arbetsytespecifikt anrop bär sitt eget workspace_id, och åtkomst avgörs
av anroparens arbetsytemedlemskap och roll – inte av att ha en
parkopplingsnyckel.
Två saker att känna till innan du exponerar porten utanför loopback:
- MCP faller stängt för anrop från andra värdar. En MCP-yta utan token svarar bara på loopback. Att binda
anyvidgar den inte – en begäran från en annan värd avvisas med ”MCP requires a bearer token to answer non-loopback clients” tills du konfigurerar en token (mcp.setToken, eller Inställningar → Server → MCP-servrar). GET /healthzär oautentiserad avsiktligt, med CORS för jokertecken, och publicerar serverns ID, namn, identitetsfingeravtryck och byggversion. Klienter behöver fingeravtrycket för att fästa servern, så det är avsiktligt – men det innebär att varje nåbarcc_serveravslöjar så mycket för vem som helst som frågar.