Přeskočit na obsah

Spusťte headless server

Spusť cc_server na stroji, který zůstane zapnutý, a připoj se k němu z počítače, prohlížeče nebo telefonu. Server je nativní binárka v čistém Dartu, bez enginu Flutteru, takže běží bez rozhraní na macOS, Linuxu i Windows. Vlastní databázi, spouští agenty a dělá každé volání externího API. Klienti jen vykreslují.

Spuštění v Dockeru (předpřipravené obrazy)

Sekce “Spuštění v Dockeru (předpřipravené obrazy)”

Každé vydání publikuje sestavu čtyř obrazů na GHCR pro vlastní hosting: backend, dva statické tenké klienty a volitelné relé párování, plus samostatný obraz cc-server-demo pro veřejného hostitele dema. Instalace s vlastním hostingem nepotřebuje checkout zdrojů. Připni tag verze (ghcr.io/samuelalev/<image>:v0.0.1-rc.1), nebo jeď na latest.

Obraz Co to je Publikuje
ghcr.io/samuelalev/cc-server Backend: databáze, agenti, MCP, webhooky -p 9030:9030
ghcr.io/samuelalev/cc-webapp Webový klient (statický nginx) -p 8080:8080
ghcr.io/samuelalev/cc-remote PWA telefonního společníka (statický nginx) -p 8081:8080
ghcr.io/samuelalev/cc-signaling-server Relé párování WebRTC (volitelné) -p 8788:8788

Celá sestava jako compose soubor:

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:

Než cokoli z toho vystavíš mimo loopback, vyplatí se vědět:

  • Obraz cc-server vozí CC_SERVER_INSECURE=1 (musí se vázat na 0.0.0.0, aby přijímal provoz z publikovaných portů), což je bezpečné jen za reverzní proxy, která ukončuje TLS (Caddy, Traefik, nginx nebo Cloudflare Tunnel), v důvěryhodné síti. Když chceš TLS ukončit přímo v procesu, připoj certifikát a nastav CC_SERVER_TLS_CERT / CC_SERVER_TLS_KEY (a pak zruš CC_SERVER_INSECURE). Všechno přepíšeš přes docker run -e … nebo blok environment: v compose.

  • /data je jediný stav. Databáze SQLite, tajemství spárovaných zařízení, stažené modely i zvuk schůzek žijí ve svazku. Zálohuj ho a kontejner je na odpis.

  • Klienta spáruj zevnitř obrazu ještě před prvním připojením, ekvivalent kontejneru ke kroku 3:

    Terminál
    docker run --rm -it -v cc_data:/data \
    --entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair
  • Oba klientské obrazy jsou statičtí hostitelé nginx. Za běhu není co nastavovat. Formulář připojení každého klienta bere URL serveru, ID zařízení a párovací klíč. Signalizační relé stejně potřebuje jen svůj port (SIGNALING_HOST / SIGNALING_PORT se dají přepsat). Je bezstavové, nedrží žádná tajemství a je to záloha: telefon použije loopback, LAN, tailnet nebo přímou cestu wss://, když je některá dosažitelná, a na relé spadne, až když žádná není. Přeskoč ho, když klienti na server dosáhnou vždy přímo.

Zbytek návodu sestavuje server ze zdrojů. Příznaky a chování, které popisuje, jsou ty samé, které do obrazu přivádějí proměnné prostředí.

  • Dart SDK. Tohle repo si SDK připíná přes fvm, takže před každý příkaz dej fvm.
  • Checkout tohoto repozitáře.
  • Nativní toolchain, který potřebuje přípravný skript: Rust/cargo, plus meson, ninja, pkg-config, git a překladač C++. Každý skript sestavení pojmenuje, co nenašel, a jak to nainstalovat.
  • Dosažitelný hostitel: loopback pro místní použití, nebo adresa v LAN či veřejná adresa s TLS pro vzdálené klienty.

Krok 1: Připrav nativní knihovny

Sekce “Krok 1: Připrav nativní knihovny”

Nativní knihovny jsou povinné. Zhoršený režim neexistuje. Sestav je z kořene repozitáře dřív než cokoli jiného:

Terminál
scripts/natives/build_natives.sh

Sestaví se rift, fff, tree-sitter i s gramatikami, aec, lame, ccpty, cc_watcher, cc_inference a nativní SAML do build/natives/. Build hook cc_server znovu vloží do balíku, co je tam připravené, takže přeskočení tohohle kroku buď sestavení rovnou shodí, nebo s únikovou cestou níže vyrobí binárku, jejíž preflight při startu odmítne naběhnout a pojmenuje chybějící knihovnu.

Terminál
cd apps/cc_server
fvm dart build cli

Balík veze libsqlite3 a připravené nativní knihovny vedle binárky. Systémové SQLite ani engine Flutteru nepotřebuje. Spustitelný soubor skončí v ./build/cli/<os_arch>/bundle/bin/cc_server.

Krok 3: Spáruj klienta před prvním startem

Sekce “Krok 3: Spáruj klienta před prvním startem”

Čerstvý datový adresář nemá spárované zařízení ani předem sdílený klíč, takže výzvu na párovací klíč klient ještě neuspokojí. Vystav ho podpříkazem pair. Zapíše global.db a secrets.json přímo. Server, který ten datový adresář už obsluhuje, nové zařízení vezme bez restartu:

Terminál
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030

Vypíše tři hodnoty, které vložíš do formuláře připojení klienta:

Connect a thin client (paste into its connect form):
Server ws://localhost:9030/rpc
Device id web-client
Pairing key <a freshly generated key>

Užitečné příznaky: --device (výchozí web-client; id zároveň volí vrstvu zařízení, tedy desktop, ios, android, a cokoli jiného je webový klient), --label (výchozí je název platformy plus hostname tohohle stroje), --host (hostitel, který se vypíše do URL, protože loopback z jiného stroje není dosažitelný) a --client-url. Opakované pair tomu zařízení otočí klíč a shodí jeho živé relace. Párování pracovní prostor nikdy nezaloží: onboarding připojujícího se klienta ten první pojmenuje a vytvoří.

S --client-url navíc vypíše QR, které se dá naskenovat z terminálu a otevře webového klienta už vyplněného:

Terminál
./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.dev

Pověření vystavené přes cc_server pair neexpiruje. Pověření vystavené v aplikaci vyprší vždy po 30 dnech. Zařízení vystavené z CLI odvolej v Nastavení → Vy → Vaše zařízení, až ho nebudeš potřebovat.

Na loopbacku, což je výchozí hodnota a všechno, co potřebuješ pro klienta na tom samém stroji:

Terminál
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030

Aby na něj dosáhl jiný stroj, navaž každé rozhraní. Vazba mimo loopback bez TLS se při startu odmítne (Refusing to bind non-loopback address … without TLS), takže dej certifikát:

Terminál
./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/rpc

Nebo ukonči TLS v reverzní proxy na důvěryhodné privátní síti a za ní se přihlas k nešifrované vazbě:

Terminál
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \
--bind any --insecure --public-url wss://server.example/rpc

--insecure se ignoruje, když jsou nastavené --tls-cert i --tls-key. TLS vždy vyhraje. Server nešifrovaný stav inzeruje jako insecure: true v GET /healthz a klienti takové spojení označí jako nezabezpečené.

Server běží do SIGINT/SIGTERM a pak se čistě vypne.

Namiř klienta na URL serveru a párovací klíč z kroku 3:

  • Aplikace pro počítač: na obrazovce prvního spuštění (Jak má Control Center běžet?) vyplň pole připojení místo Spustit v této aplikaci, nebo server přidej později v Nastavení → Server → Připojení a stav. Viz Připojte se ke vzdálenému serveru.
  • Webový klient: otevři app.usectrl.dev (nebo vlastní kopii webového sestavení) a zadej URL serveru, ID zařízení a párovací klíč.
  • Telefon: aplikaci Remote spáruj z běžícího klienta. Viz Spárujte zařízení.

Krok 6: Připoj Google Calendar (volitelné)

Sekce “Krok 6: Připoj Google Calendar (volitelné)”

Kalendář pracovního prostoru bez připojeného rozhraní synchronizuješ tokem kódu zařízení:

Terminál
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>

Vypíše kód a URL ke schválení na jiném zařízení, refresh token uloží na serveru a skončí. Sestavení ze zdrojů žádného klienta Google neveze, takže proměnné prostředí s id a secretem jsou povinné. Příznak --google-client-id neexistuje. Viz Připojte Google Calendar.

Příznaky výše stačí na první nastavení. Celá plocha, 23 dvojic příznaku a proměnné prostředí, čtyři podpříkazy a rozložení datového adresáře, je v CLI cc_server.

Čtyři, které budeš potřebovat nejspíš:

Příznak Výchozí Význam
--data-dir adresář dat aplikace pro uživatele podle OS Databáze, tajemství, modely a mezipaměť médií
--port 9030 TCP port (0 = dočasný)
--bind loopback loopback, nebo any pro každé rozhraní (chce TLS nebo --insecure)
--public-url odvozená z vazby RPC URL inzerovaná spárovaným klientům. Za proxy, NAT nebo tunelem ji nastav výslovně

Výchozí datový adresář je ~/Library/Application Support/control-center na macOS, %APPDATA%\control-center na Windows a $XDG_DATA_HOME/control-center (jinak ~/.local/share/control-center) jinde. .cc_server relativní k cwd se použije jen tehdy, když se nevyřeší domovský adresář ani adresář dat aplikace.

cc_server je celá plocha produktu, ne její výsek: datová cesta repo-RPC a odběry, endpoint nástrojů MCP na POST /mcp a GET /sse na tom samém portu, příchozí webhooky, proxy médií a písem, callbacky jednotného přihlášení, protokol zápůjčky flotily, stahování RSS na straně serveru v třicetiminutovém rytmu a vektorové hledání (rozšíření sqlite_vector se registruje jako automatické rozšíření pro celý proces a tam, kde není k dispozici, se zhorší jen na fulltextové hledání).

Dispečer je bezstavový: vazba pracovního prostoru na relaci neexistuje. Každé volání v rozsahu pracovního prostoru veze vlastní workspace_id a přístup rozhoduje členství volajícího v pracovním prostoru a jeho role, ne držení párovacího klíče.

Než port vystavíš mimo loopback, platí dvě věci:

  • MCP mimo hostitele selhává do zamítnutí. Plocha MCP bez tokenu odpovídá jen na loopback. Vazba any ji nerozšíří. Požadavek mimo hostitele se odmítne hláškou „MCP requires a bearer token to answer non-loopback clients“, dokud token nenastavíš (mcp.setToken, nebo Nastavení → Server → Servery MCP).
  • GET /healthz je schválně bez ověření, s CORS na všechny originy, a publikuje id serveru, název, otisk identity a verzi sestavení. Klienti otisk potřebují, aby si server připnuli, takže je to záměr. Znamená to ale, že každý dosažitelný cc_server tolik prozradí komukoli, kdo se zeptá.