Aller au contenu

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.

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-server livre CC_SERVER_INSECURE=1 (elle doit se lier à 0.0.0.0 pour 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éfinissez CC_SERVER_TLS_CERT / CC_SERVER_TLS_KEY (puis retirez CC_SERVER_INSECURE). Tout est modifiable avec docker run -e … ou le bloc environment: de Compose.

  • /data est 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_PORT modifiables) ; 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 chemin wss:// 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.

  • 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, plus meson, ninja, pkg-config, git et 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.

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 :

Fenêtre de terminal
scripts/natives/build_natives.sh

Cette 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.

Fenêtre de terminal
cd apps/cc_server
fvm dart build cli

Le 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 :

Fenêtre de terminal
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030

Elle 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 :

Fenêtre de terminal
./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

Un 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.

Sur la boucle locale — le réglage par défaut, et tout ce qu’il faut pour un client sur la même machine :

Fenêtre de terminal
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030

Pour 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 :

Fenêtre de terminal
./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

Ou terminez le TLS dans un proxy inverse sur un réseau privé de confiance et optez pour une liaison en clair derrière lui :

Fenêtre de terminal
./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.

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 :

Fenêtre de terminal
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.

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.

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 any ne 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 /healthz est 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 tout cc_server joignable divulgue ces renseignements à quiconque les demande.