SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-25

Auto-héberger Open Connector pour vos agents IA

Déployez Open Connector sur votre VPS sans exposer de token SaaS à vos agents : image épinglée, origine TLS, callbacks OAuth et sauvegardes SQLite.

Ce que fait Open Connector pour un agent IA

L’auto-hébergement d’Open Connector place une passerelle d’authentification entre vos agents IA et chaque API de software as a service (SaaS) qu’ils appellent. L’agent ne détient donc jamais de token de fournisseur. Il s’agit d’une passerelle open source développée par OOMOL Lab et distribuée sous licence Apache 2.0. Elle s’exécute dans un seul conteneur, conserve son état dans un fichier SQLite unique et expose les actions des fournisseurs via HTTP et MCP (model context protocol).

Le problème commence dès la deuxième intégration. Chaque fournisseur possède son propre flux OAuth (open authorization), sa propre durée de validité des refresh tokens et ses propres noms de scopes. Connecter manuellement cinq fournisseurs à un agent signifie écrire cinq gestionnaires de redirection, cinq stockages d’identifiants et cinq boucles de renouvellement qui doivent s’exécuter avant l’expiration d’un token. Presque personne n’écrit ce code. Ils créent un personal access token à longue durée pour chaque service et le copient dans la configuration de l’agent, un fichier d’environnement ou le prompt lui-même. Chaque outil exécuté par l’agent peut alors lire ce token. Il se retrouve aussi dans la transcription. C’est précisément le problème décrit dans garder les secrets hors des agents IA.

Une passerelle d’authentification sépare l’identifiant en deux parties. La passerelle stocke l’identifiant du fournisseur et exécute le flux OAuth. L’agent reçoit un runtime token valide uniquement auprès de la passerelle. Lorsque l’agent appelle une action, la passerelle charge l’identifiant stocké, l’injecte côté serveur dans la requête sortante, puis renvoie uniquement le corps de la réponse. L’agent ne reçoit jamais l’access token du fournisseur. Une transcription d’agent divulguée ne compromet donc qu’un runtime token révocable, et non votre compte GitHub.

Le catalogue annonce plus de 1,000 fournisseurs et 10,000 actions prédéfinies. Ce chiffre vient du projet lui-même et ne peut pas être vérifié de l’extérieur. Ce que vous pouvez vérifier, c’est la structure : un endpoint HTTP par action, une connexion stockée par fournisseur et un token par agent. Si la partie agent vous est encore peu familière et si des termes comme tool call ou MCP server ne sont pas encore bien établis, le parcours progressif présenté dans apprendre les agents IA en partant de zéro explique la boucle, les outils et les pratiques de sécurité qu’une passerelle de ce type suppose déjà maîtrisés.

Pourquoi auto-héberger Open Connector plutôt que d’utiliser un service de connecteur hébergé

Un service de connecteur hébergé effectue le même travail et conserve les refresh tokens de chaque fournisseur que vous lui connectez. Un refresh token Google ou GitHub est une clé longue durée donnant accès à votre messagerie et à vos dépôts. Il reste généralement valide après une modification du mot de passe. Si ce service est compromis, vous l’êtes aussi. L’auto-hébergement stocke ces enregistrements dans SQLite, sur une machine que vous louez et administrez, protégés par une clé qui ne quitte jamais votre serveur.

Évaluez clairement le coût avant de commencer. Ce VPS devient le serveur le plus sensible que vous exploitez. Il contient, dans un seul fichier, des identifiants actifs pour une douzaine de services. Vous devez donc le protéger comme un serveur hébergeant un gestionnaire de mots de passe : un firewall qui n’expose que le port 443, aucun compte partagé, une sauvegarde que vous avez réellement restaurée au moins une fois et une alerte lorsqu’il ne répond plus. Si vous ne mettriez pas votre coffre-fort de mots de passe sur cette machine, n’y installez pas non plus le connecteur.

Épinglez une version avant toute installation

Open Connector est un projet récent. Le dépôt est apparu pour la première fois le 29 June 2026. Au 1 August 2026, la version marquée la plus récente est v1.3.3, publiée le 30 July 2026, et porte également le tag latest. Le registry publie aussi un tag tip, construit à partir du commit le plus récent sur main.

Pour un projet aussi récent, les tags mobiles changent souvent. Un docker compose pull qui avance de deux versions peut modifier un endpoint dont dépend votre agent. Vous risquez alors de passer la soirée à chercher un problème dans l’agent. Épinglez l’image sur un tag de release. Effectuez la mise à niveau lorsque vous le décidez, après avoir lu les release notes.

Déployer Open Connector derrière TLS sur votre propre VPS

Avant de démarrer le conteneur, vous avez besoin des éléments suivants :

  • Docker avec le plugin Compose, sur Ubuntu 24.04 ou une version proche
  • un nom d’hôte dont l’enregistrement A pointe vers ce VPS, par exemple connect.example.com
  • un reverse proxy qui assure déjà la terminaison TLS (transport layer security) pour ce nom d’hôte
  • deux secrets aléatoires, générés ci-dessous

Le guide reverse proxy Traefik pour plusieurs applications Docker Compose couvre la configuration du proxy. La configuration complète des certificats, du début à la fin pour une seule application, se trouve dans le guide n8n sur un VPS avec Docker et HTTPS.

Générez d’abord les secrets. La clé de chiffrement protège les identifiants stockés. Le token administrateur protège la console web et toute la surface /api. Aucun des deux n’a de valeur par défaut, et le runtime démarre sans problème s’ils sont absents.

mkdir -p ~/open-connector && cd ~/open-connector
umask 077
printf 'OOMOL_CONNECT_ENCRYPTION_KEY=%s\n' "$(openssl rand -base64 32)" > .env
printf 'OOMOL_CONNECT_ADMIN_TOKEN=%s\n' "$(openssl rand -base64 32)" >> .env
chmod 600 .env

Copiez maintenant les deux valeurs dans votre gestionnaire de mots de passe, avant le premier démarrage. Il n’existe aucune procédure de récupération pour la clé de chiffrement. La liste des échecs plus bas en explique la raison.

Maintenant, compose.yaml. Il diffère de l’exemple fourni en amont sur deux points, qui sont tous les deux importants.

services:
  connector:
    image: ghcr.io/oomol-lab/open-connector:v1.3.3
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - connector-data:/app/data
    environment:
      OOMOL_CONNECT_DATA_DIR: /app/data
      OOMOL_CONNECT_ORIGIN: "https://connect.example.com"
      OOMOL_CONNECT_ENCRYPTION_KEY: "${OOMOL_CONNECT_ENCRYPTION_KEY:?set this in .env}"
      OOMOL_CONNECT_ADMIN_TOKEN: "${OOMOL_CONNECT_ADMIN_TOKEN:?set this in .env}"

volumes:
  connector-data:

Le premier changement concerne le tag épinglé au lieu de latest. Le second concerne le port. Le fichier fourni en amont publie 3000:3000, ce qui lie le port à toutes les interfaces de l’hôte. Docker écrit les ports publiés dans la table NAT (network address translation) avant que la chaîne de filtrage ufw ne voie le paquet. Par conséquent, ufw deny 3000 ne ferme pas ce port : c’est le piège décrit dans pourquoi les ports Docker contournent ufw. Écrire 127.0.0.1:3000:3000 publie le port sur l’interface loopback uniquement, et votre reverse proxy se connecte depuis le même hôte.

Le :? indique que chaque variable est obligatoire. La stack refuse donc de démarrer si .env est absent, au lieu de démarrer avec des identifiants non chiffrés. Conserver les valeurs dans .env plutôt que dans le fichier Compose suit le modèle présenté dans fichiers env et secrets Docker Compose.

docker compose up -d
docker compose logs -n 30 connector
curl -s http://127.0.0.1:3000/health
sudo ss -tlnp | grep 3000

/health répond { "ok": true } une fois que le runtime est démarré. ss doit afficher 127.0.0.1:3000. Une ligne contenant 0.0.0.0:3000 signifie que le mapping de port utilise encore celui du fichier fourni en amont et que la gateway répond directement à tout Internet. Une erreur « Connection refused » lors du health check signifie que le conteneur n’écoute pas encore. Consultez donc les journaux avant de modifier le proxy.

Labels Traefik pour le même service
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.connector.rule=Host(`connect.example.com`)"
      - "traefik.http.routers.connector.entrypoints=websecure"
      - "traefik.http.routers.connector.tls.certresolver=le"
      - "traefik.http.services.connector.loadbalancer.server.port=3000"

Lorsque Traefik s’exécute dans Docker sur le même hôte, rattachez ce service au réseau Traefik et supprimez le bloc ports:, car Traefik atteint le conteneur via le réseau interne et aucun port ne doit être publié sur l’hôte. certresolver=le doit correspondre au nom du resolver dans votre configuration statique Traefik. Sinon, le routeur démarre sans certificat.

Pourquoi OAuth exige un véritable nom d’hôte

OOMOL_CONNECT_ORIGIN est le paramètre que l’on oublie souvent. Cet oubli casse OAuth d’une manière qui ressemble à un bug du fournisseur. Le runtime construit l’URI de redirection à partir de cette origine, sous la forme <origin>/oauth/callback. Si cette valeur n’est pas définie, l’origine devient par défaut http://localhost:3000. Le runtime envoie donc au fournisseur l’URI de redirection http://localhost:3000/oauth/callback, alors que votre application OAuth a enregistré https://connect.example.com/oauth/callback. Les deux chaînes diffèrent. GitHub répond alors :

The redirect_uri MUST match the registered callback URL for this application.

Un fournisseur OAuth redirige le navigateur vers cette URI. Il faut donc qu’elle corresponde à une adresse accessible depuis l’extérieur. Les fournisseurs refusent les adresses http:// simples, sauf pour localhost. C’est la seule raison pour laquelle ce déploiement a besoin d’un nom d’hôte et d’un certificat. Définissez l’origine avant le premier démarrage, car sa valeur est lue au démarrage. Après avoir modifié .env ou compose.yaml, exécutez de nouveau docker compose up -d pour appliquer la modification.

Connecter votre premier provider avec OAuth

Créez d’abord l’application OAuth chez le provider. Sur GitHub, accédez à Settings, puis Developer settings, puis OAuth Apps, puis New OAuth App. Définissez l’URL de callback d’autorisation sur https://connect.example.com/oauth/callback. Conservez le client ID et le client secret.

Chaque appel à /api inclut le token d’administration. Exportez-le donc une seule fois pour la session shell.

export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
  -H "authorization: Bearer $ADMIN_TOKEN"

Cette liste affiche l’URI de redirection attendue par le runtime pour chaque provider. C’est donc la vérification la plus rapide pour confirmer que votre origin est bien prise en compte. Si elle indique encore localhost, le conteneur utilise l’ancienne valeur et le flux OAuth échouera à la dernière étape.

Enregistrez les identifiants client, puis démarrez une autorisation.

curl -s -X PUT https://connect.example.com/api/oauth/configs/github \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"clientId":"...","clientSecret":"..."}'

curl -s -X POST https://connect.example.com/api/oauth/authorizations \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"service":"github"}'

Le deuxième appel renvoie un authorizationUrl. Ouvrez-le dans un navigateur et approuvez les scopes. Le provider redirige ensuite le navigateur vers /oauth/callback. Le runtime y échange le code et enregistre l’identifiant d’authentification. La console web disponible sur votre origin guide les mêmes étapes avec un formulaire, derrière le même token d’administration. Les providers qui utilisent une simple clé API ignorent toutes ces étapes : PUT /api/connections/<service> avec {"authType":"api_key","values":{"apiKey":"..."}} enregistre directement la clé.

Donnez à chaque agent un token d’exécution, jamais l’identifiant d’authentification

L’agent s’authentifie auprès de la gateway avec un token d’exécution, que l’API d’administration génère.

curl -s -X POST https://connect.example.com/api/runtime-tokens \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"name":"research-agent"}'

La réponse contient un token commençant par oct_. Créez-en un par agent et nommez-le d’après cet agent, car révoquer un token que vous ne pouvez pas identifier revient à tous les révoquer. L’agent appelle ensuite les actions via HTTP standard.

curl -s -X POST https://connect.example.com/v1/actions/github.get_current_user \
  -H "authorization: Bearer oct_..." \
  -H 'content-type: application/json' \
  -d '{"input":{}}'

Une réponse saine est une enveloppe dont le champ success vaut true, avec la payload du provider dans data. Le token GitHub ne figure nulle part dans cette réponse. Pour un client MCP, configurez-le avec https://connect.example.com/mcp et le même header bearer. La gateway fournit alors des outils de découverte comme search_actions et execute_action, au lieu d’un outil par API, ce qui limite la taille de la liste d’outils de l’agent. Exécuter des serveurs MCP sur un VPS couvre la partie client de cette configuration.

Effectuez encore une vérification avant de considérer l’installation comme terminée. Répétez l’appel d’action après avoir supprimé le header authorization. Le quickstart du projet appelle lui-même /v1 sans bearer. Une installation sans authentification d’exécution configurée exécutera donc les actions pour toute personne pouvant atteindre le port. Si votre appel non authentifié réussit, deux solutions sont possibles : configurez les tokens d’exécution et vérifiez que l’appel anonyme échoue désormais, ou restreignez /api, /v1 et /mcp au niveau du reverse proxy aux adresses utilisées par vos agents. Seul /oauth/callback doit rester ouvert sur Internet, car c’est l’unique chemin nécessaire à la redirection du navigateur d’un provider.

Réduire la liste d’actions à ce dont l’agent a besoin

Une gateway qui donne accès à mille providers présente une large surface d’exposition pour un modèle de langage. Cette surface s’élargit dès que le modèle commence à lire du texte qu’il n’a pas écrit. Une page renvoyée par votre propre instance SearXNG qui répond aux recherches web de l’agent peut contenir des instructions visant les actions auxquelles l’agent a accès. La même retenue qui pousse un agent de codage à appliquer la plus petite modification fonctionnelle doit s’appliquer à ses permissions : accordez uniquement les quelques actions nécessaires à la tâche, et rien de plus. Deux contrôles permettent de limiter cet accès.

OOMOL_CONNECT_ALLOWED_ACTIONS accepte une allowlist séparée par des virgules et prend en charge service.* et *. OOMOL_CONNECT_BLOCKED_ACTIONS est la denylist, qui est prioritaire. Définir l’allowlist sur github.get_current_user,github.list_issues signifie que toutes les autres actions sont refusées, quelle que soit la demande de l’agent. C’est ce qui fait la différence entre une erreur et un incident. Les runtime tokens appliquent leurs propres règles d’action en plus des règles globales. Leur liste allowedProxies est vide par défaut, donc POST /v1/proxy/:service est refusée tant que vous ne l’avez pas autorisée. Cet endpoint de proxy transmet une requête brute à un provider avec vos identifiants. Laissez-le donc vide, sauf si un agent précis en a besoin.

OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK prend par défaut la valeur false. Cela empêche une connexion vers un provider self-hosted de pointer vers une adresse privée, comme le service de métadonnées cloud sur 169.254.169.254 ou votre base de données présente sur le même réseau. Laissez cette option désactivée. Activez-la uniquement pour un provider que vous hébergez vous-même.

Sauvegarder le serveur qui contient tous les tokens

Deux éléments sont nécessaires, et chacun est inutile sans l’autre. La base de données située dans /app/data/connect.sqlite, à l’intérieur du volume connector-data, contient les identifiants chiffrés. La clé de chiffrement située dans .env permet de les déchiffrer. Une sauvegarde du volume sans la clé ne restaure rien, et la clé sans le volume ne restaure rien non plus. La clé doit donc être stockée dans votre gestionnaire de mots de passe, et le volume doit être inclus dans votre rotation de sauvegardes habituelle.

Arrêtez le conteneur pendant la copie du fichier SQLite. Une copie effectuée pendant une écriture peut restaurer une base de données corrompue.

docker volume ls | grep connector-data
docker compose stop connector
docker run --rm -v open-connector_connector-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/connector-data.tgz -C /data .
docker compose start connector

Le nom du volume correspond à votre répertoire de projet suivi de _connector-data. C’est la raison de la première commande : collez le nom réel dans la troisième. Transférez l’archive hors du VPS avec restic pour sauvegarder un VPS. restic la chiffre avant son transfert, car cette archive contient le stockage des identifiants.

Le runtime conserve les exécutions récentes des actions sous forme d’enregistrements d’audit, 5,000 par défaut. La console peut ainsi indiquer quel agent a exécuté quelle action et à quel moment. Consultez d’abord ce journal lorsqu’un agent se comporte de manière étrange. Configurez également une page d’état Uptime Kuma pour surveiller https://connect.example.com/health. Lorsque la gateway ne répond plus, les agents échouent de manière difficile à interpréter. Savoir que la gateway est hors service évite de passer une heure à lire la sortie des agents.

Ce qui échoue et le message affiché

redirect_uri_mismatch chez le fournisseur. L’origine et l’URL de callback enregistrée sont différentes. Comparez la chaîne exacte de /api/oauth/configs avec les paramètres de l’application chez le fournisseur, notamment https et http, ainsi que l’éventuel slash final.

Chaque appel /api renvoie 401. L’en-tête contenant le token d’administration est absent ou mal orthographié. L’en-tête est Authorization: Bearer <token>, et la console web demande le même token.

Le conteneur s’exécute et les identifiants sont stockés en clair. Cela se produit lorsque OOMOL_CONNECT_ENCRYPTION_KEY n’atteint jamais le conteneur, car le runtime stocke les enregistrements d’identifiants sans chiffrement au lieu de refuser de démarrer. Vérifiez-le sur votre propre installation : connectez un fournisseur avec une API key identifiable, puis recherchez-la dans la base de données.

docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqlite

Un nombre supérieur à 0 signifie que la clé n’est pas prise en compte. Vérifiez donc que .env se trouve dans le même répertoire que compose.yaml et que docker compose config affiche la valeur. Une fois la clé définie, la même recherche renvoie 0, car l’enregistrement est chiffré avec AES-256-GCM (advanced encryption standard, clé de 256 bits, mode Galois/counter).

Rien ne peut être déchiffré après une restauration. La clé de chiffrement a changé ou a été perdue. Elle n’est jamais écrite à côté des données, par conception. Il n’existe donc aucune procédure de récupération et aucun ticket de support ne peut résoudre le problème. Reconnectez chaque fournisseur. La rotation est prise en charge par une variable de clé distincte et une commande de données du runtime. Consultez donc les notes de version actuelles avant toute rotation.

L’agent renvoie une erreur qui mentionne une action visible dans le catalogue. La découverte et l’exécution sont distinctes. Une action peut apparaître dans search_actions tout en étant refusée par OOMOL_CONNECT_ALLOWED_ACTIONS, par la denylist ou par les propres règles du token du runtime.

Mises à niveau. Sauvegardez le volume, modifiez le tag de l’image pour utiliser la nouvelle release, puis docker compose pull && docker compose up -d. Surveillez docker compose logs -n 50 connector pour repérer une ligne de migration, puis relancez le health check et une action réelle avant de considérer le système comme opérationnel. Pour revenir à l’ancienne version, restaurez l’ancien tag. Cela fonctionne uniquement parce que vous l’avez épinglé.

FAQ

Ai-je besoin d’un domaine public pour auto-héberger Open Connector ?

Pour les fournisseurs qui utilisent une clé API, non : une gateway sur 127.0.0.1 suffit. Pour OAuth, oui en pratique. Le fournisseur redirige un navigateur vers votre URL de callback. Cette URL doit donc être accessible depuis Internet, et les fournisseurs refusent généralement http:// en dehors de localhost. Définissez OOMOL_CONNECT_ORIGIN sur votre hostname https:// avant le premier démarrage, puis enregistrez <origin>/oauth/callback dans l’application OAuth du fournisseur.

Que se passe-t-il si je perds la clé de chiffrement d’Open Connector ?

Les identifiants enregistrés ne peuvent plus être déchiffrés, et il n’existe aucune récupération possible. La clé n’est volontairement jamais stockée avec les données. Toute personne qui détient la base de données ne peut donc pas la lire, vous y compris. Votre seule option consiste à définir une nouvelle clé et à reconnecter chaque fournisseur. Conservez la clé dans un gestionnaire de mots de passe et la base de données dans votre rotation de sauvegardes, car une restauration nécessite les deux.

Mon agent IA peut-il voir le token d’accès du fournisseur ?

Pas lorsqu’il appelle le fournisseur via la gateway. L’agent s’authentifie avec un token runtime commençant par oct_. La gateway injecte l’identifiant du fournisseur dans la requête sortante sur le serveur, puis renvoie uniquement la réponse. Deux situations annulent cette protection : l’endpoint /v1/proxy/:service, qui transmet des requêtes brutes avec votre identifiant, et dont les grants sont vides pour une bonne raison ; et le fait de coller vous-même une clé API dans l’agent, ce qui contourne entièrement la gateway.

La gateway doit-elle être accessible depuis Internet ?

Seul /oauth/callback doit l’être. Publiez le port du conteneur sur 127.0.0.1 afin que les règles NAT de Docker ne puissent pas l’exposer au-delà de votre firewall, puis placez le reverse proxy devant. Testez ensuite un appel d’action sans en-tête authorization. S’il réussit, limitez /api, /v1 et /mcp au niveau du proxy aux adresses utilisées par vos agents, jusqu’à ce que seuls les appels authentifiés fonctionnent.

Open Connector est-il prêt pour une utilisation en production ?

Le projet est sous licence Apache 2.0 et évolue rapidement : le repository est apparu le 29 June 2026 et v1.3.3 est sorti le 30 July 2026. Considérez donc chaque numéro de version de ce guide comme un instantané au 1 August 2026. Exécutez-le en le verrouillant sur un release tag, jamais sur latest ou tip. Lisez les release notes avant chaque upgrade et conservez une sauvegarde du volume que vous avez déjà restaurée une fois. La conception est fiable pour une machine que vous administrez. Le risque vient de la fréquence des changements de version, pas de l’architecture.