Esegui un server headless
Esegui cc_server su una macchina sempre accesa, poi connettiti dal desktop, da
un browser o dal telefono. Il server è un binario nativo scritto in puro Dart —
nessun engine Flutter — quindi gira headless su macOS, Linux o Windows. Possiede
il database, esegue gli agent e fa ogni chiamata alle API esterne; i client si
limitano a mostrare.
Esegui in Docker (immagini precompilate)
Sezione intitolata “Esegui in Docker (immagini precompilate)”Ogni release pubblica uno stack self-hosted di quattro immagini GHCR — il
backend, i due thin client statici e il relay di abbinamento opzionale — più una
immagine separata cc-server-demo per l’host della demo pubblica. Un’installazione
self-hosted non richiede alcun checkout del sorgente. Fissa un tag di versione
(ghcr.io/samuelalev/<image>:v0.0.1-rc.1) oppure segui latest.
| Immagine | Cos’è | Pubblica |
|---|---|---|
ghcr.io/samuelalev/cc-server |
Il backend: database, agent, MCP, webhook | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Il client web (nginx statico) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
La PWA complementare per telefono (nginx statico) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
Il relay di abbinamento WebRTC (opzionale) | -p 8788:8788 |
L’intero stack come file 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:Cose che vale la pena sapere prima di esporre tutto questo oltre il loopback:
-
L’immagine
cc-serverincludeCC_SERVER_INSECURE=1(deve fare il bind su0.0.0.0per ricevere il traffico della porta pubblicata), condizione sicura solo dietro un reverse proxy che termina il TLS — Caddy, Traefik, nginx o un Cloudflare Tunnel — su una rete affidabile. Per terminare invece il TLS nel processo, monta un certificato e impostaCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(poi rimuoviCC_SERVER_INSECURE). Tutto è sovrascrivibile condocker run -e …o con il bloccoenvironment:del compose. -
/dataè l’unico stato. I database SQLite, i segreti dei dispositivi associati, i modelli scaricati e l’audio delle riunioni vivono tutti nel volume: fanne un backup e il container diventa usa e getta. -
Associa un client dall’interno dell’immagine prima della prima connessione, l’equivalente in container del passaggio 3:
Finestra del terminale docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
Le due immagini client sono host nginx statici — niente da configurare a runtime; il modulo di connessione di ogni client accetta l’URL del server, l’ID dispositivo e la chiave di abbinamento. Anche il relay di signaling ha bisogno solo della sua porta (
SIGNALING_HOST/SIGNALING_PORTsovrascrivibili); è senza stato, non conserva segreti ed è un fallback: un telefono usa il loopback, la LAN, il tailnet o un percorsowss://diretto quando uno è raggiungibile, e ripiega sul relay solo quando nessuno lo è. Salta il relay se i tuoi client raggiungono sempre il server direttamente.
Il resto di questa guida compila il server dal sorgente; i flag e il comportamento che descrive sono gli stessi alimentati dalle variabili d’ambiente dell’immagine.
Prerequisiti
Sezione intitolata “Prerequisiti”- Il Dart SDK. Questo repo fissa la sua SDK con fvm, quindi anteponi
fvma ogni comando. - Questo repository con il checkout effettuato.
- La toolchain nativa richiesta dallo script di preparazione — Rust/
cargo, piùmeson,ninja,pkg-config,gite un compilatore C++. Ogni script di build indica ciò che non riesce a trovare e come installarlo. - Un host raggiungibile: il loopback per l’uso locale, oppure un indirizzo LAN/pubblico con TLS per i client remoti.
Passaggio 1: prepara le librerie native
Sezione intitolata “Passaggio 1: prepara le librerie native”Le librerie native sono obbligatorie: non esiste una modalità degradata. Compilale dalla radice del repo prima di ogni altra cosa:
scripts/natives/build_natives.shQuesta compila rift, fff, tree-sitter con le sue grammatiche, aec, lame,
ccpty, cc_watcher, cc_inference e il nativo SAML in
build/natives/. L’hook di build di cc_server
riversa nel bundle qualunque cosa sia stata preparata lì, quindi saltare questo
passaggio fa fallire la build del tutto oppure — con la scappatoia qui sotto —
produce un binario il cui preflight di avvio si rifiuta di partire e indica la
libreria mancante.
Passaggio 2: compila il binario
Sezione intitolata “Passaggio 2: compila il binario”cd apps/cc_serverfvm dart build cliIl bundle include libsqlite3 e le librerie native preparate accanto al
binario — non servono SQLite di sistema né l’engine Flutter. L’eseguibile finisce
in ./build/cli/<os_arch>/bundle/bin/cc_server.
Passaggio 3: associa un client prima del primo avvio
Sezione intitolata “Passaggio 3: associa un client prima del primo avvio”Una directory dati appena creata non ha alcun dispositivo associato e nessuna
chiave precondivisa, quindi la richiesta della chiave di abbinamento di un client
non può ancora essere soddisfatta. Generane una con il sottocomando pair.
Scrive direttamente global.db e secrets.json; un server che sta già servendo
quella directory dati rileva il nuovo dispositivo senza riavvio:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Stampa tre valori da incollare nel modulo di connessione di un client:
Connect a thin client (paste into its connect form): Server ws://localhost:9030/rpc Device id web-client Pairing key <a freshly generated key>Flag utili: --device (predefinito web-client; l’id determina anche la fascia
del dispositivo — desktop, ios, android, qualsiasi altro valore è un client
web), --label (predefinito al nome della piattaforma più l’hostname di questa
macchina), --host (l’host da stampare nell’URL, dato che il loopback non è
raggiungibile da un’altra macchina) e --client-url. Rieseguire pair ruota la
chiave di quel dispositivo e chiude le sue sessioni attive. L’abbinamento non
crea mai uno spazio di lavoro: l’onboarding del client che si connette nomina e
crea il primo.
Con --client-url stampa anche un codice QR scansionabile dal terminale che apre
il client web già compilato:
./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.devUna credenziale generata da cc_server pair non ha alcuna scadenza; una
generata nell’app scade sempre dopo 30 giorni. Revoca un dispositivo creato dalla
CLI da Impostazioni → Tu → I tuoi dispositivi quando hai finito di usarlo.
Passaggio 4: avvia il server
Sezione intitolata “Passaggio 4: avvia il server”Su loopback — l’impostazione predefinita e tutto ciò che serve per un client sulla stessa macchina:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030Per raggiungerlo da un’altra macchina, fai il bind su ogni interfaccia. Un bind
non di loopback senza TLS viene rifiutato all’avvio (Refusing to bind non-loopback address … without TLS), quindi fornisci un certificato:
./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/rpcOppure termina il TLS in un reverse proxy su una rete privata affidabile e attiva un bind in chiaro dietro di esso:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpc--insecure viene ignorato quando --tls-cert e --tls-key sono entrambi
impostati: vince sempre il TLS. Il server dichiara lo stato in chiaro come
insecure: true in GET /healthz e i client contrassegnano una connessione di
questo tipo come non sicura.
Il server resta in esecuzione fino a SIGINT/SIGTERM, poi si arresta in modo
pulito.
Passaggio 5: connetti un client
Sezione intitolata “Passaggio 5: connetti un client”Punta un client all’URL del server e alla chiave di abbinamento del passaggio 3:
- App desktop: nella schermata di primo avvio (Come eseguire Control Center?) compila i campi di connessione invece di Esegui in questa app, oppure aggiungi il server in un secondo momento in Impostazioni → Server → Connessione e stato. Vedi Connettiti a un server remoto.
- Client web: apri app.usectrl.dev (o la tua copia della build web) e inserisci l’URL del server, l’ID dispositivo e la chiave di abbinamento.
- Telefono: associa l’app Remote da un client in esecuzione — vedi Associa un dispositivo.
Passaggio 6: collega un Google Calendar (opzionale)
Sezione intitolata “Passaggio 6: collega un Google Calendar (opzionale)”Per sincronizzare il calendario di uno spazio di lavoro senza alcuna GUI collegata, usa il flusso con codice dispositivo:
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>Stampa un codice e un URL da approvare su un altro dispositivo, memorizza il
refresh token lato server ed esce. Una build dal sorgente non include alcun
client Google, quindi le variabili d’ambiente con id e secret sono obbligatorie:
non esiste un flag --google-client-id. Vedi
Collega un Google Calendar.
Configurazione
Sezione intitolata “Configurazione”I flag usati sopra sono quelli necessari a una prima configurazione. La
superficie completa — 23 coppie di flag e variabili d’ambiente, i quattro
sottocomandi e la struttura della directory dati — è nel
riferimento della CLI di cc_server.
I quattro che ti serviranno più probabilmente:
| Flag | Predefinito | Significato |
|---|---|---|
--data-dir |
la directory dei dati applicazione per utente del sistema operativo | Database, segreti, modelli e media in cache |
--port |
9030 |
Porta TCP (0 = effimera) |
--bind |
loopback |
loopback, oppure any per ogni interfaccia (richiede TLS o --insecure) |
--public-url |
derivato dal bind | L’URL RPC annunciato ai client associati. Impostalo esplicitamente dietro un proxy, un NAT o un tunnel |
La directory dati predefinita è ~/Library/Application Support/control-center su
macOS, %APPDATA%\control-center su Windows e
$XDG_DATA_HOME/control-center (altrimenti ~/.local/share/control-center)
altrove. Un .cc_server relativo alla cwd viene usato solo quando non si risolve
alcuna home o directory di dati applicazione.
Cosa espone il server
Sezione intitolata “Cosa espone il server”cc_server è l’intera superficie del prodotto, non un sottoinsieme: il percorso
dati e le sottoscrizioni repo-RPC, l’endpoint degli strumenti MCP su POST /mcp
e GET /sse sulla stessa porta, i webhook in ingresso, i proxy di media e font,
i callback di single sign-on, il protocollo di lease della flotta, il recupero
RSS lato server con una pianificazione di 30 minuti e la ricerca vettoriale
(l’estensione sqlite_vector è registrata come auto-extension globale del
processo, e degrada alla sola ricerca full-text dove l’estensione non è
disponibile).
Il dispatcher è senza stato: non esiste alcun binding di spazio di lavoro per
sessione. Ogni chiamata con ambito di spazio di lavoro porta con sé il proprio
workspace_id e l’accesso è deciso dall’appartenenza e dal ruolo del chiamante
nello spazio di lavoro, non dal possesso di una chiave di abbinamento.
Due cose da sapere prima di esporre la porta oltre il loopback:
- L’MCP adotta un comportamento restrittivo fuori dall’host. Una superficie MCP senza token risponde solo al loopback. Il bind
anynon la amplia: una richiesta esterna all’host viene rifiutata con “MCP requires a bearer token to answer non-loopback clients” finché non ne configuri uno (mcp.setToken, oppure Impostazioni → Server → Server MCP). GET /healthznon è autenticato per scelta, ha CORS con wildcard e pubblica l’id, il nome, l’impronta dell’identità e la versione di build del server. I client hanno bisogno dell’impronta per fare il pin del server, quindi è deliberato — ma significa che qualsiasicc_serverraggiungibile divulga tutte queste informazioni a chiunque le chieda.
Guide correlate
Sezione intitolata “Guide correlate”- Connettiti a un server remoto
- Associa un dispositivo
- Esegui un worker della flotta
- Collega un Google Calendar