Uruchom serwer headless
Uruchom cc_server na maszynie, która jest stale włączona, a następnie połącz się
z nim ze swojego pulpitu, przeglądarki lub telefonu. Serwer to natywna binarka
napisana w czystym Dart — bez silnika Flutter — więc działa headless w systemach
macOS, Linux i Windows. Jest właścicielem bazy danych, uruchamia agentów i wykonuje
wszystkie wywołania zewnętrznych API; klienty tylko renderują interfejs.
Uruchamianie w Dockerze (gotowe obrazy)
Dział zatytułowany „Uruchamianie w Dockerze (gotowe obrazy)”Każde wydanie publikuje hostowany samodzielnie stos czterech obrazów GHCR —
backend, dwa statyczne cienkie klienty i opcjonalny przekaźnik parowania — a
także osobny obraz cc-server-demo dla publicznego hosta demonstracyjnego.
Instalacja hostowana samodzielnie nie wymaga pobierania źródeł. Przypnij tag
wersji (ghcr.io/samuelalev/<image>:v0.0.1-rc.1) albo korzystaj z latest.
| Obraz | Co to jest | Publikuje |
|---|---|---|
ghcr.io/samuelalev/cc-server |
Backend: baza danych, agenci, MCP, webhooki | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Klient webowy (statyczny nginx) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
Towarzysząca aplikacja PWA na telefon (statyczny nginx) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
Przekaźnik parowania WebRTC (opcjonalny) | -p 8788:8788 |
Cały stos jako plik compose:
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:O czym warto wiedzieć, zanim wystawisz to wszystko poza loopback:
-
Obraz
cc-serverzawieraCC_SERVER_INSECURE=1(musi nasłuchiwać na0.0.0.0, aby odbierać ruch z opublikowanych portów), co jest bezpieczne tylko za terminującym TLS odwrotnym proxy — Caddy, Traefik, nginx lub Cloudflare Tunnel — w zaufanej sieci. Aby zamiast tego terminować TLS w samym procesie, zamontuj certyfikat i ustawCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(a następnie usuńCC_SERVER_INSECURE). Wszystko można nadpisać za pomocądocker run -e …lub blokuenvironment:w compose. -
/datato cały stan. Bazy SQLite, sekrety sparowanych urządzeń, pobrane modele i dźwięk ze spotkań — wszystko to mieszka w wolumenie; zrób jego kopię zapasową, a kontener stanie się jednorazowy. -
Sparuj klienta z wnętrza obrazu przed pierwszym połączeniem — to kontenerowy odpowiednik kroku 3:
Okno terminala docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
Oba obrazy klientów to statyczne hosty nginx — niczego nie trzeba konfigurować w czasie działania; formularz połączenia każdego klienta przyjmuje adres URL serwera, identyfikator urządzenia i klucz parowania. Przekaźnik sygnalizacyjny również potrzebuje wyłącznie swojego portu (
SIGNALING_HOST/SIGNALING_PORTmożna nadpisać); jest bezstanowy, nie przechowuje żadnych sekretów i stanowi mechanizm awaryjny — telefon korzysta z loopbacku, sieci LAN, tailnetu albo bezpośredniej ścieżkiwss://, gdy któraś z nich jest osiągalna, a sięga po przekaźnik tylko wtedy, gdy żadna nie jest. Pomiń go, jeśli Twoi klienci zawsze łączą się z serwerem bezpośrednio.
Dalsza część tego poradnika buduje serwer ze źródeł; omawiane tu flagi i zachowanie to te same, które zasilają zmienne środowiskowe obrazu.
Wymagania wstępne
Dział zatytułowany „Wymagania wstępne”- Dart SDK. To repozytorium przypina swoje SDK za pomocą fvm, więc każdą komendę poprzedź prefiksem
fvm. - Sklonowane to repozytorium.
- Natywny łańcuch narzędzi wymagany przez skrypt przygotowujący — Rust/
cargoorazmeson,ninja,pkg-config,giti kompilator C++. Każdy skrypt budowania wskazuje, czego nie potrafi znaleźć i jak to zainstalować. - Osiągalny host: loopback do użytku lokalnego albo adres LAN/publiczny z TLS dla klientów zdalnych.
Krok 1: Przygotuj biblioteki natywne
Dział zatytułowany „Krok 1: Przygotuj biblioteki natywne”Biblioteki natywne są wymagane — nie istnieje tryb zdegradowany. Zbuduj je z katalogu głównego repozytorium, zanim zrobisz cokolwiek innego:
scripts/natives/build_natives.shTo buduje rift, fff, tree-sitter wraz z jego gramatykami, aec, lame,
ccpty, cc_watcher, cc_inference oraz bibliotekę natywną SAML do
build/natives/. Hak budowania cc_server
ponownie emituje do pakietu wszystko, co zostało tam przygotowane, więc pominięcie
tego kroku albo od razu powoduje błąd budowania, albo — dzięki furtce awaryjnej
opisanej poniżej — daje binarkę, której kontrola wstępna podczas rozruchu odmawia
uruchomienia i wskazuje brakującą bibliotekę.
Krok 2: Zbuduj binarkę
Dział zatytułowany „Krok 2: Zbuduj binarkę”cd apps/cc_serverfvm dart build cliPakiet zawiera libsqlite3 i przygotowane biblioteki natywne obok binarki — nie
potrzeba systemowego SQLite ani silnika Flutter. Plik wykonywalny trafia do
./build/cli/<os_arch>/bundle/bin/cc_server.
Krok 3: Sparuj klienta przed pierwszym uruchomieniem
Dział zatytułowany „Krok 3: Sparuj klienta przed pierwszym uruchomieniem”Świeży katalog danych nie ma sparowanego urządzenia ani współdzielonego klucza,
więc monitu klienta o klucz parowania nie da się jeszcze zaspokoić. Wygeneruj taki
klucz podkomendą pair. Zapisuje ona bezpośrednio pliki global.db i
secrets.json; serwer, który już obsługuje ten katalog danych, wykryje nowe
urządzenie bez restartu:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Wyświetla trzy wartości do wklejenia w formularz połączenia 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>Przydatne flagi: --device (domyślnie web-client; identyfikator wybiera też
klasę urządzenia — desktop, ios, android, cokolwiek innego to klient
webowy), --label (domyślnie nazwa platformy plus nazwa hosta tej maszyny),
--host (host wypisywany w adresie URL, ponieważ loopback nie jest osiągalny z
innej maszyny) oraz --client-url. Ponowne uruchomienie pair rotuje klucz tego
urządzenia i porzuca jego aktywne sesje. Parowanie nigdy nie tworzy obszaru
roboczego: robi to onboarding łączącego się klienta, nadając nazwę i tworząc
pierwszy obszar.
Z opcją --client-url wypisuje też kod QR do zeskanowania z terminala, który
otwiera klienta webowego z już wypełnionymi danymi:
./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.devPoświadczenie wygenerowane przez cc_server pair nie ma terminu ważności; to
wygenerowane w aplikacji zawsze wygasa po 30 dniach. Gdy urządzenie utworzone z
CLI przestanie być potrzebne, odwołaj je w
Ustawienia → Ty → Twoje urządzenia.
Krok 4: Uruchom serwer
Dział zatytułowany „Krok 4: Uruchom serwer”Na loopbacku — to ustawienie domyślne i wszystko, czego potrzebujesz dla klienta na tej samej maszynie:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030Aby uzyskać do niego dostęp z innej maszyny, powiąż wszystkie interfejsy.
Powiązanie z adresem innym niż loopback bez TLS jest odrzucane przy starcie
(Refusing to bind non-loopback address … without TLS), więc dostarcz certyfikat:
./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/rpcAlbo terminuj TLS w odwrotnym proxy w zaufanej sieci prywatnej i zdecyduj się na nieszyfrowane powiązanie za nim:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpc--insecure jest ignorowane, gdy ustawione są jednocześnie --tls-cert i
--tls-key — TLS zawsze wygrywa. Serwer ogłasza stan nieszyfrowany jako
insecure: true w GET /healthz, a klienty oznaczają takie połączenie jako
niezabezpieczone.
Serwer działa aż do SIGINT/SIGTERM, po czym zamyka się czysto.
Krok 5: Połącz klienta
Dział zatytułowany „Krok 5: Połącz klienta”Skieruj klienta na adres URL serwera i klucz parowania z kroku 3:
- Aplikacja desktopowa: na ekranie pierwszego uruchomienia (Jak ma działać Control Center?) wypełnij pola połączenia zamiast Uruchom w tej aplikacji, albo dodaj serwer później w Ustawienia → Serwer → Połączenie i status. Zobacz Połącz się ze zdalnym serwerem.
- Klient webowy: otwórz app.usectrl.dev (lub własną kopię kompilacji webowej) i podaj adres URL serwera, identyfikator urządzenia oraz klucz parowania.
- Telefon: sparuj aplikację Remote z działającego klienta — zobacz Sparuj urządzenie.
Krok 6: Połącz Google Calendar (opcjonalnie)
Dział zatytułowany „Krok 6: Połącz Google Calendar (opcjonalnie)”Aby zsynchronizować kalendarz obszaru roboczego bez podłączonego interfejsu graficznego, użyj przepływu kodu urządzenia:
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>Wypisuje kod i adres URL do zatwierdzenia na innym urządzeniu, zapisuje token
odświeżania po stronie serwera i kończy działanie. Kompilacja ze źródeł nie
zawiera klienta Google, więc zmienne środowiskowe z identyfikatorem i sekretem są
wymagane — nie ma flagi --google-client-id. Zobacz
Połącz Google Calendar.
Konfiguracja
Dział zatytułowany „Konfiguracja”Flagi użyte powyżej to te, których potrzebuje pierwsza konfiguracja. Pełny zakres —
23 pary flag i zmiennych środowiskowych, cztery podkomendy oraz układ katalogu
danych — znajdziesz w dokumentacji referencyjnej CLI cc_server.
Cztery, które najprawdopodobniej Ci się przydadzą:
| Flaga | Wartość domyślna | Znaczenie |
|---|---|---|
--data-dir |
katalog danych aplikacji dla użytkownika w danym systemie | Bazy danych, sekrety, modele i pamięć podręczna multimediów |
--port |
9030 |
Port TCP (0 = efemeryczny) |
--bind |
loopback |
loopback albo any dla wszystkich interfejsów (wymaga TLS lub --insecure) |
--public-url |
wyprowadzany z powiązania | Adres URL RPC ogłaszany sparowanym klientom. Ustaw go jawnie za proxy, NAT lub tunelem |
Domyślny katalog danych to ~/Library/Application Support/control-center w
systemie macOS, %APPDATA%\control-center w systemie Windows oraz
$XDG_DATA_HOME/control-center (a w przeciwnym razie
~/.local/share/control-center) w pozostałych systemach. Katalog .cc_server
względny wobec bieżącego katalogu roboczego jest używany tylko wtedy, gdy nie da
się ustalić katalogu domowego ani katalogu danych aplikacji.
Co serwuje serwer
Dział zatytułowany „Co serwuje serwer”cc_server to cała powierzchnia produktu, a nie jej podzbiór: ścieżka danych
repo-RPC i subskrypcje, endpoint narzędzi MCP pod POST /mcp i GET /sse na tym
samym porcie, przychodzące webhooki, proxy multimediów i fontów, wywołania zwrotne
logowania jednokrotnego, protokół dzierżawy floty, pobieranie RSS po stronie
serwera według 30-minutowego harmonogramu oraz wyszukiwanie wektorowe (rozszerzenie
sqlite_vector jest rejestrowane jako auto-rozszerzenie globalne dla procesu,
degradując do wyszukiwania pełnotekstowego tylko tam, gdzie rozszerzenie jest
niedostępne).
Dyspozytor jest bezstanowy: nie ma powiązania obszaru roboczego z sesją. Każde
wywołanie w zakresie obszaru roboczego niesie własny workspace_id, a o dostępie
decyduje członkostwo i rola wywołującego w obszarze roboczym — nie posiadanie
klucza parowania.
Dwie rzeczy, o których warto wiedzieć, zanim wystawisz port poza loopback:
- MCP działa w trybie fail-closed poza hostem. Powierzchnia MCP bez tokenu odpowiada tylko na loopbacku. Powiązanie
anytego nie rozszerza — żądanie spoza hosta jest odrzucane komunikatem „MCP requires a bearer token to answer non-loopback clients”, dopóki nie skonfigurujesz tokenu (mcp.setTokenalbo Ustawienia → Serwer → Serwery MCP). GET /healthzjest celowo nieuwierzytelnione, ma wieloznaczne CORS i publikuje identyfikator serwera, jego nazwę, odcisk tożsamości i wersję kompilacji. Klienty potrzebują odcisku, aby przypiąć serwer, więc jest to zamierzone — oznacza to jednak, że każdy osiągalnycc_serverujawnia tyle każdemu, kto o to zapyta.