Déploiement Remote Hub
Un hub conserve les identifiants fournisseur, le catalogue et l’usage sur un hôte. Les clients authentifiés appellent directement son plan de données. Le plan de gestion est distinct : son écoute facultative reste sur 127.0.0.1 et ne sert que le tableau de bord et /api/*. Elle ne sert jamais /v1/*, /healthz, /readyz ni WebSocket. Ne publiez pas le port 10101 et n’utilisez pas Tailscale Funnel.
Rôles, connexion et sécurité
Section intitulée « Rôles, connexion et sécurité »standalone réunit données et gestion. hub possède les secrets fournisseur et l’usage. client ne conserve que l’état de connexion et une clé de données dédiée.
ocx connect https://hub-name.tailnet-name.ts.net --pairing-code-stdinocx connect statusocx syncLa clé client est écrite dans le fichier privé service-api-token, jamais dans config.json. En mode connecté, l’usage provient du hub et est filtré par apiKeyId; après déconnexion, il provient du stockage local. Il n’existe aucune réplication entre les deux.
Le jeton admin permet la gestion ordinaire mais ne peut jamais créer une session de consentement. Les actions de consentement exigent une gui-session, une Origin correspondante et un jeton CSRF. Tailscale-User-Login n’est fiable que sur l’entrée de gestion dédiée; renseignez les identités exactes dans remoteGui.allowedTailscaleUsers.
Service et Tailscale Serve
Section intitulée « Service et Tailscale Serve »ocx config set runtimeRole hubocx config set hostname 100.64.0.10ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"'ocx config set corsAllowOrigins '["http://localhost:10100"]'ocx config set hub.managementIngress '{"enabled":true,"port":10101}'ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]'export OPENCODEX_API_AUTH_TOKEN="$(openssl rand -hex 32)"ocx service installLe service lit le secret depuis service-api-token; le plist ou l’unité systemd ne contient pas sa valeur.
curl --fail --silent http://100.64.0.10:10100/healthzcurl --fail --silent http://100.64.0.10:10100/readyztailscale serve --bg --https=443 http://127.0.0.1:10101tailscale serve status/healthz ne prouve que la vie du processus. Validez aussi /readyz, GET /v1/catalog authentifié et une vraie réponse routée. Le port de gestion doit écouter uniquement sur 127.0.0.1. Pour un proxy TLS privé, utilisez tailscale cert hub-name.tailnet-name.ts.net et ne fabriquez jamais d’en-têtes Tailscale-User-*; utilisez l’association à usage unique.
OAuth, rotation et déconnexion
Section intitulée « OAuth, rotation et déconnexion »ocx config set oauthOpenBrowser falseocx connect rotate --pairing-code-stdin# uniquement en HTTPS :ocx connect rotate --admin-token-stdinDémarrez OAuth avec POST /api/oauth/login; si le rappel ne rejoint pas le hub, envoyez l’URL finale ou le code à POST /api/oauth/login/code sous {provider,input}. Ne placez jamais le code OAuth dans argv ou les journaux.
La rotation garde les deux clés valides sous le même apiKeyId pendant dix minutes au plus. L’ancienne clé est sauvegardée dans service-api-token.prev, la nouvelle est installée atomiquement et vérifiée avec /v1/catalog, puis validée. Si le résultat est incertain, relancez ocx connect rotate avec une autorité transitoire; ne supprimez aucun candidat.
ocx disconnect restaure l’état local même hors ligne et ne révoque pas la clé du hub. Après déconnexion, la seule voie de révocation est Integrations → API Keys sur le hub. ocx connect revoke --admin-token-stdin fonctionne uniquement tant que le client est connecté.
Docker, retour arrière et dépannage
Section intitulée « Docker, retour arrière et dépannage »Il n’existe pas d’image Docker officielle, mais le dépôt fournit un Dockerfile et un compose.yaml maintenus pour construire localement une image Bun épinglée par digest. Initialisez une seule fois la clé de données via stdin ; elle est enregistrée avec des permissions réservées au propriétaire dans le volume ocx-state et n’est jamais affichée.
Installez Git et Bun sur l’hôte. Avant chaque construction, générez le manifeste canonique depuis les sources suivies par Git, sans modifier les sources entre la génération et la construction. Le JSON généré reste non suivi ; .git est exclu du contexte Docker. Le port hôte est lié à 127.0.0.1 par défaut. Pour un accès distant, utilisez explicitement OPENCODEX_BIND_ADDRESS=<IP-LAN-ou-Tailscale> docker compose up -d ; 0.0.0.0 expose toutes les interfaces. Protégez cet accès par un pare-feu et un frontal TLS/tailnet authentifié.
La construction rejette les manifestes périmés en comparant chaque SHA-256 aux fichiers du contexte puis de l’image. Les fichiers manquants ou divergents, les sources supplémentaires et les liens symboliques sont refusés. package.json, bun.lock et le seul fichier autorisé de scripts/, scripts/model-metadata.source.json, sont obligatoires.
git clone https://github.com/lidge-jun/opencodex.gitcd opencodexbun scripts/generate-compatibility-version.tsdocker compose buildopenssl rand -hex 32 | docker compose run --rm -T hub bun run docker/bootstrap-token.tsdocker compose up -dLe conteneur s’exécute avec l’utilisateur non-root bun, un système de fichiers racine en lecture seule et uniquement le port 10100 publié. Ne publiez jamais 10101 et ne placez aucun secret dans ARG, ENV, COPY, Compose, l’historique d’image ou argv. Après le healthcheck, vérifiez séparément /readyz, le catalogue authentifié et une réponse réelle. docker compose down conserve le volume ; docker compose down --volumes supprime aussi la configuration, les identifiants et la clé.
- Hub indisponible :
ocx disconnectrestaure localement, mais la révocation reste à faire. - Catalogue périmé : seul un dernier catalogue validé est conservé après une panne transitoire; aucune substitution locale après erreur d’authentification, schéma, taille ou protocole.
- Récupération
.prev: conservez les deux fichiers et relancez la rotation avec une autorité transitoire. hub-too-new/hub-too-old: mettez à niveau le côté indiqué avant toute écriture locale.- Code d’association perdu ou épuisé : créez-en un nouveau; les essais sont limités avec 429.
- HTTP non local exige
--allow-insecure-http; un jeton admin n’est jamais envoyé en HTTP. - Déconnexion/expiration de session navigateur n’affecte pas la clé de données.
- Avant
tailscale serve reset, inspecteztailscale serve status, car reset supprime tous les mappages.

