Exécuter un serveur sans interface
Exécutez cc_server sur une machine qui reste allumée, puis connectez-vous à
celui-ci depuis votre ordinateur de bureau, un navigateur ou votre téléphone. Le
serveur est un binaire natif en Dart pur — aucun moteur Flutter — et fonctionne
donc sans interface sur macOS, Linux ou Windows. Il détient la base de données,
exécute les agents et effectue tous les appels aux API externes ; les clients ne
font que l’affichage.
Exécuter dans Docker (images préconstruites)
Section intitulée « Exécuter dans Docker (images préconstruites) »Chaque version publiée fournit une pile auto-hébergée de quatre images GHCR — le
backend, les deux clients légers statiques et le relais d’appairage facultatif —
ainsi qu’une image cc-server-demo distincte pour l’hôte de démonstration public.
Une installation auto-hébergée n’exige aucune copie du code source. Épinglez une
étiquette de version (ghcr.io/samuelalev/<image>:v0.0.1-rc.1) ou suivez
latest.
| Image | Ce que c’est | Ports publiés |
|---|---|---|
ghcr.io/samuelalev/cc-server |
Le backend : base de données, agents, MCP, webhooks | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Le client web (nginx statique) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
La PWA compagnon pour téléphone (nginx statique) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
Le relais d’appairage WebRTC (facultatif) | -p 8788:8788 |
Toute la pile sous forme de fichier 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:Ce qu’il faut savoir avant d’exposer tout cela au-delà de la boucle locale :
-
L’image
cc-serverlivreCC_SERVER_INSECURE=1(elle doit se lier à0.0.0.0pour recevoir le trafic des ports publiés), ce qui n’est sûr que derrière un proxy inverse qui termine le TLS — Caddy, Traefik, nginx ou un tunnel Cloudflare — sur un réseau de confiance. Pour terminer le TLS dans le processus à la place, montez un certificat et définissezCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(puis retirezCC_SERVER_INSECURE). Tout est modifiable avecdocker run -e …ou le blocenvironment:de Compose. -
/dataest le seul état. Les bases de données SQLite, les secrets des appareils associés, les modèles téléchargés et l’audio des réunions vivent tous dans le volume — sauvegardez-le et le conteneur devient jetable. -
Associez un client depuis l’intérieur de l’image avant la première connexion, l’équivalent en conteneur de l’étape 3 :
Fenêtre de terminal docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
Les deux images client sont des hôtes nginx statiques — rien à configurer à l’exécution ; le formulaire de connexion de chaque client demande l’URL du serveur, l’identifiant d’appareil et la clé d’appairage. Le relais de signalisation n’a lui aussi besoin que de son port (
SIGNALING_HOST/SIGNALING_PORTmodifiables) ; il est sans état, ne détient aucun secret et n’est qu’un repli — un téléphone utilise la boucle locale, le réseau local, le tailnet ou un cheminwss://direct quand l’un d’eux est joignable, et ne se replie sur le relais que si aucun ne l’est. Omettez-le si vos clients joignent toujours le serveur directement.
Le reste de ce guide compile le serveur à partir des sources ; les options et le comportement qu’il couvre sont exactement ceux qu’alimentent les variables d’environnement de l’image.
Prérequis
Section intitulée « Prérequis »- Le SDK Dart. Ce dépôt épingle son SDK avec fvm, alors préfixez chaque commande par
fvm. - Ce dépôt cloné sur votre machine.
- La chaîne d’outils native dont le script de préparation a besoin — Rust/
cargo, plusmeson,ninja,pkg-config,gitet un compilateur C++. Chaque script de compilation nomme ce qu’il ne trouve pas et comment l’installer. - Un hôte joignable : la boucle locale pour un usage local, ou une adresse de réseau local/publique avec TLS pour des clients distants.
Étape 1 : Préparer les bibliothèques natives
Section intitulée « Étape 1 : Préparer les bibliothèques natives »Les bibliothèques natives sont obligatoires — il n’existe pas de mode dégradé. Compilez-les depuis la racine du dépôt avant toute autre chose :
scripts/natives/build_natives.shCette commande compile rift, fff, tree-sitter et ses grammaires, aec, lame,
ccpty, cc_watcher, cc_inference et la bibliothèque native SAML dans
build/natives/. Le crochet de compilation de cc_server réémet dans le paquet
tout ce qui y a été préparé ; sauter cette étape fait donc échouer la compilation
d’emblée ou — avec l’échappatoire ci-dessous — produit un binaire dont la
vérification préalable au démarrage refuse de démarrer et nomme la bibliothèque
manquante.
Étape 2 : Compiler le binaire
Section intitulée « Étape 2 : Compiler le binaire »cd apps/cc_serverfvm dart build cliLe paquet livre libsqlite3 et les bibliothèques natives préparées à côté du
binaire — aucun SQLite système ni moteur Flutter n’est nécessaire. L’exécutable se
trouve à ./build/cli/<os_arch>/bundle/bin/cc_server.
Étape 3 : Associer un client avant le premier démarrage
Section intitulée « Étape 3 : Associer un client avant le premier démarrage »Un répertoire de données neuf ne contient aucun appareil associé ni clé pré-partagée,
l’invite de clé d’appairage d’un client ne peut donc pas encore être satisfaite.
Créez-en une avec la sous-commande pair. Elle écrit global.db et secrets.json
directement ; un serveur qui sert déjà ce répertoire de données prend le nouvel
appareil en compte sans redémarrage :
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Elle imprime trois valeurs à coller dans le formulaire de connexion d’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>Options utiles : --device (par défaut web-client ; l’identifiant détermine aussi
le palier de l’appareil — desktop, ios, android, tout le reste est un client
web), --label (par défaut, le nom de la plateforme suivi du nom d’hôte de cette
machine), --host (l’hôte à imprimer dans l’URL, puisque la boucle locale n’est pas
joignable depuis une autre machine) et --client-url. Relancer pair renouvelle la
clé de cet appareil et coupe ses sessions actives. L’association ne crée jamais
d’espace de travail : l’intégration initiale du client qui se connecte nomme et crée
le premier.
Avec --client-url, elle imprime aussi un QR code scannable depuis un terminal qui
ouvre le client web déjà rempli :
./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.devUn identifiant d’appairage émis par cc_server pair ne comporte aucune
expiration ; un identifiant émis dans l’application expire toujours après 30 jours.
Révoquez un appareil créé par la CLI depuis Paramètres → Vous → Vos appareils
lorsque vous n’en avez plus besoin.
Étape 4 : Démarrer le serveur
Section intitulée « Étape 4 : Démarrer le serveur »Sur la boucle locale — le réglage par défaut, et tout ce qu’il faut pour un client sur la même machine :
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030Pour l’atteindre depuis une autre machine, liez toutes les interfaces. Une liaison
hors boucle locale sans TLS est refusée au démarrage (Refusing to bind non-loopback address … without TLS), fournissez donc un certificat :
./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/rpcOu terminez le TLS dans un proxy inverse sur un réseau privé de confiance et optez pour une liaison en clair derrière lui :
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpc--insecure est ignoré lorsque --tls-cert et --tls-key sont tous deux définis —
le TLS l’emporte toujours. Le serveur annonce l’état en clair sous la forme
insecure: true dans GET /healthz et les clients signalent une telle connexion
comme non sécurisée.
Le serveur fonctionne jusqu’à SIGINT/SIGTERM, puis s’arrête proprement.
Étape 5 : Connecter un client
Section intitulée « Étape 5 : Connecter un client »Pointez un client vers l’URL du serveur et la clé d’appairage de l’étape 3 :
- Application de bureau : à l’écran du premier lancement (Comment exécuter Control Center ?), remplissez les champs de connexion au lieu de Exécuter dans cette application, ou ajoutez le serveur plus tard sous Paramètres → Serveur → Connexion et état. Voir Se connecter à un serveur distant.
- Client web : ouvrez app.usectrl.dev (ou votre propre copie de la compilation web) et saisissez l’URL du serveur, l’identifiant d’appareil et la clé d’appairage.
- Téléphone : associez l’application Remote depuis un client en cours d’exécution — voir Associer un appareil.
Étape 6 : Connecter un Google Calendar (facultatif)
Section intitulée « Étape 6 : Connecter un Google Calendar (facultatif) »Pour synchroniser le calendrier d’un espace de travail sans interface graphique, utilisez le flux de code d’appareil :
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>Elle imprime un code et une URL à approuver sur un autre appareil, stocke le jeton
d’actualisation côté serveur et se termine. Une compilation à partir des sources ne
livre aucun client Google, les variables d’environnement de l’identifiant et du
secret sont donc obligatoires — il n’existe aucune option --google-client-id. Voir
Connecter un Google Calendar.
Configuration
Section intitulée « Configuration »Les options utilisées ci-dessus sont celles dont une première installation a besoin.
La surface complète — 23 paires d’options et de variables d’environnement, les
quatre sous-commandes et la disposition du répertoire de données — se trouve dans la
référence de la CLI cc_server.
Les quatre dont vous aurez le plus probablement besoin :
| Option | Valeur par défaut | Signification |
|---|---|---|
--data-dir |
le répertoire de données d’application par utilisateur du système | Bases de données, secrets, modèles et médias en cache |
--port |
9030 |
Port TCP (0 = éphémère) |
--bind |
loopback |
loopback, ou any pour toutes les interfaces (nécessite TLS ou --insecure) |
--public-url |
dérivée de la liaison | L’URL RPC annoncée aux clients associés. Définissez-la explicitement derrière un proxy, un NAT ou un tunnel |
Le répertoire de données par défaut est ~/Library/Application Support/control-center sur macOS,
%APPDATA%\control-center sur Windows et $XDG_DATA_HOME/control-center (sinon
~/.local/share/control-center) ailleurs. Un .cc_server relatif au répertoire
courant n’est utilisé que lorsqu’aucun répertoire de base ou de données
d’application ne peut être résolu.
Ce que sert le serveur
Section intitulée « Ce que sert le serveur »cc_server couvre toute la surface du produit, et non un sous-ensemble : le chemin
de données et les abonnements du RPC de dépôt, le point de terminaison d’outils MCP
à POST /mcp et GET /sse sur le même port, les webhooks entrants, les proxys de
médias et de polices, les rappels d’authentification unique, le protocole de bail de
la flotte, la récupération RSS côté serveur selon un horaire de 30 minutes et la
recherche vectorielle (l’extension sqlite_vector est enregistrée comme
auto-extension globale au processus, et ne se dégrade en recherche plein texte que
là où l’extension est indisponible).
Le répartiteur est sans état : il n’existe aucune liaison d’espace de travail par
session. Chaque appel propre à un espace de travail porte son propre workspace_id
et l’accès est décidé par l’appartenance et le rôle de l’appelant dans l’espace de
travail — et non par la possession d’une clé d’appairage.
Deux choses à savoir avant d’exposer le port au-delà de la boucle locale :
- MCP échoue en mode fermé hors de l’hôte. Une surface MCP sans jeton ne répond qu’à la boucle locale. La liaison
anyne l’élargit pas — une requête hors hôte est refusée avec « MCP requires a bearer token to answer non-loopback clients » jusqu’à ce que vous en configuriez un (mcp.setToken, ou Paramètres → Serveur → Serveurs MCP). GET /healthzest non authentifié par conception, avec un CORS générique, et publie l’identifiant, le nom, l’empreinte d’identité et la version de compilation du serveur. Les clients ont besoin de l’empreinte pour épingler le serveur, c’est donc délibéré — mais cela signifie que toutcc_serverjoignable divulgue ces renseignements à quiconque les demande.
Guides connexes
Section intitulée « Guides connexes »- Se connecter à un serveur distant
- Associer un appareil
- Exécuter un worker de flotte
- Connecter un Google Calendar