Open ConnectorをAIエージェント向けに自宅運用する方法
Open ConnectorをVPSでセルフホストし、固定イメージ、TLS origin、OAuth callbacks、バックアップを設定します。AIエージェントにSaaS tokenを保持させない構成です。
Open ConnectorがAIエージェントに提供する機能
Open Connectorをセルフホストすると、AIエージェントと、エージェントが呼び出すすべてのsoftware as a service (SaaS) APIの間に、1つの認証ゲートウェイを配置できます。そのため、エージェントがprovider tokenを保持する必要はありません。これはOOMOL Labが提供するオープンソースのゲートウェイで、Apache 2.0ライセンスです。1つのコンテナとして動作し、状態を1つのSQLiteファイルに保存します。また、providerのアクションをHTTPとMCP (model context protocol)で公開します。
問題は、2つ目の統合から始まります。各providerには、独自のOAuth (open authorization)フロー、独自のrefresh tokenの有効期間、独自のscope名があります。5つのproviderをエージェントに手動で接続するには、5つのredirect handler、5つのcredential store、トークンの有効期限前に実行する必要がある5つのrefresh loopが必要です。このコードを書く人はほとんどいません。そのため、サービスごとに有効期間の長いpersonal access tokenを1つ発行し、それをエージェントの設定、環境ファイル、またはプロンプト自体に貼り付けます。そのトークンは、エージェントが実行するすべてのツールから読み取れる状態になります。また、トランスクリプトにも記録されます。これは、AIエージェントから秘密情報を除外するで説明している問題です。
認証ゲートウェイは、credentialを2つに分離します。ゲートウェイがprovider credentialを保存し、OAuthフローを実行します。エージェントが取得するのは、ゲートウェイに対してのみ有効なruntime tokenです。エージェントがアクションを呼び出すと、ゲートウェイは保存済みのcredentialを読み込み、サーバー側で送信リクエストに注入し、レスポンスボディだけを返します。エージェントがprovider access tokenを受け取ることはありません。そのため、エージェントのトランスクリプトが漏えいしても、失うのはGitHubアカウントそのものではなく、失効させられるruntime token 1つです。
カタログでは1,000を超えるproviderと10,000の事前構築済みアクションを掲載しています。ただし、これはプロジェクト独自の数値であり、外部から検証できるものではありません。検証できるのは構成です。各アクションに1つのHTTP endpoint、各providerに1つの保存済みconnection、各エージェントに1つのtokenがあります。
ホスト型コネクターサービスではなく Open Connector をセルフホストする理由
ホスト型コネクターサービスでも同じ処理を実行できます。ただし、接続するすべてのプロバイダーの refresh token をそのサービスが保持します。Google や GitHub の refresh token は、メールやリポジトリへの長期的なアクセス権を持つキーです。通常、パスワードを変更しても有効なままです。サービスが侵害されると、あなたの環境も侵害されます。セルフホストすると、これらの記録は自分で借りて管理するマシン上の SQLite に保存されます。鍵で保護され、その鍵がマシンの外部に出ることはありません。
開始する前に、コストを明確に把握してください。この VPS は、運用する中で最も価値の高いサーバーになります。1つのファイルに12個のサービスの有効な認証情報を保存するため、パスワードマネージャーのホストと同じ扱いが必要です。ファイアウォールで公開するのは 443 のみとし、共有ログインを使わず、実際に一度は復元したバックアップを用意し、応答が停止したときにアラートを出します。このマシンにパスワード保管庫を置けないなら、コネクターも置かないでください。
インストール前にバージョンを固定する
Open Connector は新しいソフトウェアです。リポジトリが初めて登場したのは 29 June 2026 で、1 August 2026 時点の最新のタグ付きリリースは v1.3.3 です。このリリースは 30 July 2026 に公開され、latest タグも付いています。レジストリでは main の最新コミットからビルドされた tip タグも公開されています。
このように新しいプロジェクトでは、移動するタグが頻繁に変わります。2つのリリースを飛び越えて更新される docker compose pull によって、エージェントが依存するエンドポイントが変更される可能性があります。その結果、エージェントの問題だと考えて、夜通しデバッグすることになります。イメージはリリースタグに固定し、リリースノートを読んだうえで、必要なときにアップグレードしてください。
独自のVPS上でTLS対応のOpen Connectorをデプロイする
コンテナを起動する前に、次のものが必要です。
- Composeプラグインを含むDocker。Ubuntu 24.04またはそれに近い環境
- AレコードがこのVPSを指すホスト名。例:
connect.example.com - そのホスト名のTLS(transport layer security)をすでに終端しているリバースプロキシ
- 以下で生成する2つのランダムなシークレット
複数のDocker Composeアプリ用Traefikリバースプロキシでは、プロキシ側を説明しています。単一アプリについて、証明書の設定から完了までを扱う同様のガイドは、DockerとHTTPSを使用したVPS上のn8nです。
最初にシークレットを生成します。暗号化キーは保存済みの認証情報を保護します。管理者トークンはWebコンソールと/api全体を保護します。どちらにもデフォルト値はなく、これらがなくてもランタイムは問題なく起動します。
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最初の起動前に、両方の値をパスワードマネージャーへコピーしてください。暗号化キーには復旧手段がありません。その理由は、後述の障害一覧に記載されています。
次にcompose.yamlします。上流の例とは2箇所異なり、どちらも重要です。
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:1つ目の変更は、latestではなくタグを固定していることです。2つ目はポートです。上流のファイルは3000:3000を公開します。これはホスト上のすべてのインターフェースにバインドします。Dockerは、ufwのフィルターチェーンがパケットを確認する前に、公開ポートをNAT(network address translation)テーブルへ書き込みます。そのため、ufw deny 3000ではそのポートを閉じられません。これはDockerのポートがufwをバイパスする理由で説明している落とし穴です。127.0.0.1:3000:3000と記述すると、ループバックインターフェースだけに公開され、リバースプロキシは同じホストから接続します。
:?は各変数を必須としてマークします。そのため、.envがない場合、認証情報を暗号化せずに起動するのではなく、スタックの起動に失敗します。値をcomposeファイルではなく.envに保持する方法は、Docker Composeのenvファイルとシークレットで説明しているパターンです。
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はランタイムの起動後に{ "ok": true }へ応答します。ssは127.0.0.1:3000を出力する必要があります。0.0.0.0:3000と表示される場合、ポートマッピングはまだ上流の設定のままで、ゲートウェイがインターネット全体に直接応答しています。ヘルスチェックでConnection refusedになる場合、コンテナはまだリッスンしていません。プロキシを変更する前にログを確認してください。
同じサービス用のTraefikラベル
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"Traefikが同じホスト上のDockerで動作している場合は、このサービスをTraefikネットワークに接続し、ports:ブロックを削除してください。Traefikは内部ネットワーク経由でコンテナに接続するため、ホストへ公開する必要はありません。certresolver=leは、Traefikの静的設定にあるリゾルバー名と一致する必要があります。一致しない場合、ルーターは証明書なしで起動します。
OAuthで実在するホスト名が必要になる理由
OOMOL_CONNECT_ORIGIN は省略されがちな設定です。省略すると、OAuthでプロバイダーの不具合のように見えるエラーが発生します。ランタイムは、このオリジンからリダイレクトURIを <origin>/oauth/callback の形式で生成します。オリジンが未設定の場合、デフォルトで http://localhost:3000 になります。そのため、ランタイムはプロバイダーに http://localhost:3000/oauth/callback のリダイレクトURIを送信します。一方、OAuthアプリには https://connect.example.com/oauth/callback が登録されています。2つの文字列が異なるため、GitHubは次のように応答します。
The redirect_uri MUST match the registered callback URL for this application.OAuthプロバイダーはブラウザーをそのURIへリダイレクトします。そのため、そのURIは外部から到達できるアドレスでなければなりません。また、プロバイダーはlocalhost以外の通常の http:// を拒否します。これが、このデプロイにホスト名と証明書が必要な理由です。オリジンの値は起動時に読み込まれるため、初回起動の前に設定してください。.env または compose.yaml を編集した後、適用するにはもう一度 docker compose up -d を実行します。
最初のプロバイダーを OAuth で接続する
まず、プロバイダーで OAuth アプリを作成します。GitHub では、Settings、Developer settings、OAuth Apps、New OAuth App の順に移動します。認証コールバック URL に https://connect.example.com/oauth/callback を設定します。client ID と client secret を控えておきます。
すべての /api 呼び出しには admin token が必要なため、シェルセッション用に一度だけ export します。
export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
-H "authorization: Bearer $ADMIN_TOKEN"この一覧には、各プロバイダーでランタイムが想定するリダイレクト URI が表示されます。origin が反映されたことを最もすばやく確認できます。まだ localhost と表示される場合、コンテナーは古い値で実行されています。そのため、OAuth フローは最後の手順で失敗します。
client credentials を保存してから、認証を開始します。
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"}'2つ目の呼び出しは authorizationUrl を返します。これをブラウザーで開いてスコープを承認すると、プロバイダーはブラウザーを /oauth/callback に戻します。ランタイムはそこで code を交換し、credential を保存します。origin の Web コンソールでも、同じ admin token のもとでフォームを使って同じ手順を実行できます。通常の API key を使用するプロバイダーでは、この手順は不要です。PUT /api/connections/<service> と {"authType":"api_key","values":{"apiKey":"..."}} を使用すると、key が直接保存されます。
各エージェントに認証情報ではなくランタイムトークンを付与する
エージェントは、管理APIが発行するランタイムトークンでゲートウェイに認証します。
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"}'レスポンスには、oct_ で始まるトークンが含まれます。エージェントごとに1つ発行し、そのエージェントの名前を付けてください。識別できないトークンを失効させると、すべてのトークンを失効させることになるためです。エージェントは通常のHTTPでアクションを呼び出します。
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":{}}'正常な応答は、success フィールドが true で、プロバイダーのペイロードが data の下にあるエンベロープです。GitHubトークンは、その応答のどこにも含まれていません。MCPクライアントでは、同じbearerヘッダーを使用して https://connect.example.com/mcp を指定します。ゲートウェイは、APIごとに1つのツールを提供するのではなく、search_actions や execute_action などの検出用ツールを提供します。これにより、エージェントのツール一覧を小さく保てます。VPSでMCPサーバーを実行するでは、この接続のクライアント側を説明しています。
完了と判断する前に、もう1つ確認します。authorization ヘッダーを削除して、同じアクション呼び出しを繰り返します。プロジェクト独自のクイックスタートでは、bearerなしで /v1 を呼び出しています。そのため、ランタイム認証を設定していないインストールでは、ポートに到達できるユーザーなら誰でもアクションを実行できます。認証なしの呼び出しが成功した場合は、2つの対処方法があります。ランタイムトークンを設定し、匿名の呼び出しが失敗することを確認します。または、リバースプロキシで /api、/v1、/mcp をエージェントの送信元アドレスに制限します。世界中に公開したままにする必要があるのは /oauth/callback だけです。これは、プロバイダーのブラウザーリダイレクトに必要な唯一の経路だからです。
エージェントに必要なアクションだけに絞る
背後に1000個のプロバイダーがあるゲートウェイは、言語モデルに与える対象として広すぎます。2つの制御で範囲を絞れます。
OOMOL_CONNECT_ALLOWED_ACTIONSにはカンマ区切りの許可リストを指定でき、service.*と*にも対応しています。OOMOL_CONNECT_BLOCKED_ACTIONSは拒否リストで、拒否リストが優先されます。許可リストをgithub.get_current_user,github.list_issuesに設定すると、エージェントが何を要求しても、それ以外のすべてのアクションが拒否されます。これは単なるミスとインシデントを分ける設定です。実行時トークンにはグローバル設定に加えて独自のアクションルールが適用されます。トークンのallowedProxiesリストは空で始まるため、許可を与えるまでPOST /v1/proxy/:serviceは拒否されます。このプロキシエンドポイントは、認証情報を付加して生のリクエストをプロバイダーに転送します。そのため、特定のエージェントに必要な場合を除き、空のままにしてください。
OOMOL_CONNECT_ALLOW_PRIVATE_NETWORKのデフォルト値はfalseです。これにより、自ホスト型プロバイダーの接続が、169.254.169.254のクラウドメタデータサービスや同じネットワーク上のデータベースなど、プライベートアドレスを指すことを防ぎます。無効のままにしてください。自分でホストしているプロバイダーに対してのみ有効にします。
すべてのトークンを保持するボックスをバックアップする
重要なのは2つあり、どちらももう一方がなければ役に立ちません。connector-data ボリューム内の /app/data/connect.sqlite にあるデータベースには、暗号化された認証情報が保存されています。.env にある暗号鍵で、それらを復号します。鍵のないボリュームバックアップからは何も復元できません。ボリュームのない鍵からも何も復元できません。そのため、鍵はパスワードマネージャーに保管し、ボリュームは通常のバックアップローテーションに含めてください。
SQLite ファイルをコピーする間はコンテナを停止してください。書き込み中に取得したコピーは、復元時にデータベースが破損する可能性があります。
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ボリューム名はプロジェクトディレクトリに _connector-data を付けたものです。そのため、最初のコマンドで実際の名前を確認し、3つ目のコマンドに貼り付けます。VPSからのresticバックアップを使用してアーカイブをVPSの外部に送信してください。アーカイブは送信前に暗号化されます。このアーカイブが認証情報ストアだからです。
ランタイムは、デフォルトで5,000件の最近のアクション実行を監査レコードとして保持します。これにより、コンソールでどのエージェントがいつ何を実行したかを確認できます。エージェントの動作が不自然な場合は、まずこのログを確認してください。https://connect.example.com/health も Uptime Kumaのステータスページで監視してください。ゲートウェイが応答を停止すると、エージェントは分かりにくい形で失敗します。ゲートウェイが停止していることが分かれば、エージェントの出力を1時間読む必要がなくなります。
何が壊れ、どのメッセージが表示されるか
プロバイダー側で redirect_uri_mismatch。 オリジンと登録済みのコールバックURLが一致していません。/api/oauth/configs の正確な文字列をプロバイダーのアプリ設定と比較してください。https と http の対応や、末尾のスラッシュも確認します。
すべての /api 呼び出しが 401 を返す。 管理者トークンのヘッダーがないか、名前が誤っています。ヘッダーは Authorization: Bearer <token> です。Webコンソールでも同じトークンを指定します。
コンテナは実行されるが、認証情報が平文で保存される。 OOMOL_CONNECT_ENCRYPTION_KEY がコンテナに届いていない場合に発生します。runtime は認証情報のレコードを暗号化せずに保存し、起動を拒否しないためです。自分の環境で確認できます。認識できるAPIキーを使用してプロバイダーを接続し、そのキーをデータベースで検索してください。
docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqlite0より大きい件数は、キーが有効になっていないことを示します。.env が compose.yaml と同じディレクトリにあること、および docker compose config に値が表示されることを確認してください。キーを設定すると、同じ検索結果は0になります。レコードがAES-256-GCM(advanced encryption standard、256ビットキー、Galois/counter mode)で暗号化されるためです。
復元後に何も復号できない。 暗号化キーが変更されたか、失われています。設計上、キーはデータの隣には保存されません。そのため復旧手段はなく、サポートチケットでも解決できません。すべてのプロバイダーを再接続してください。ローテーションには別のキー変数とruntime内のデータコマンドを使用します。何かをローテーションする前に、現在のリリースノートを確認してください。
カタログに表示されるアクションをエージェントが実行すると、そのアクション名を含むエラーが発生する。 検出と実行は別の処理です。アクションが search_actions に表示されていても、OOMOL_CONNECT_ALLOWED_ACTIONS、denylist、またはそのruntimeトークン固有のルールによって拒否されることがあります。
アップグレード。 ボリュームをバックアップし、イメージタグを新しいリリースに変更してから、docker compose pull && docker compose up -d を実行します。docker compose logs -n 50 connector を監視してマイグレーションの行を確認し、再度ヘルスチェックと実際のアクションを1つ実行してから、運用に戻してください。ロールバックでは古いタグに戻します。タグを固定している場合に限り、これで動作します。
FAQ
Open Connectorをセルフホストするにはパブリックドメインが必要ですか?
API keyを使用するプロバイダーでは不要です。127.0.0.1上のゲートウェイで十分です。OAuthでは、実際には必要です。プロバイダーはブラウザーをコールバックURLへリダイレクトするため、そのURLはパブリックインターネットから名前解決できなければなりません。また、プロバイダーはlocalhost以外でのプレーンなhttp://を拒否します。初回起動前にOOMOL_CONNECT_ORIGINをhttps://ホスト名へ設定し、プロバイダーのOAuthアプリに<origin>/oauth/callbackを登録してください。
Open Connectorの暗号化キーを失うとどうなりますか?
保存された認証情報を復号できなくなり、復旧手段はありません。このキーは意図的にデータと同じ場所へ保存されないため、データベースを持つ誰も読み取れません。あなた自身も読み取れません。唯一の方法は新しいキーを設定し、すべてのプロバイダーを再接続することです。キーはpassword managerに保管し、データベースはバックアップのローテーションに含めてください。リストアには両方が必要です。
AIエージェントはプロバイダーのaccess tokenを参照できますか?
ゲートウェイ経由で呼び出す場合は参照できません。エージェントはoct_で始まるruntime tokenで認証します。ゲートウェイはサーバー上の送信リクエストにプロバイダーの認証情報を挿入し、レスポンスだけを返します。この性質を損なうものは2つあります。1つ目は/v1/proxy/:serviceエンドポイントです。このエンドポイントは認証情報を付けた生のリクエストを転送します。付与権限が最初は空なのは、そのためです。2つ目は、エージェントに自分でAPI keyを貼り付けることです。この場合、ゲートウェイを完全に迂回します。
ゲートウェイをパブリックインターネットから到達可能にすべきですか?
/oauth/callbackだけを到達可能にする必要があります。コンテナのポートを127.0.0.1に公開し、DockerのNATルールがファイアウォールの外側へ公開できないようにしてください。リバースプロキシはその前に配置します。次に、authorizationヘッダーなしで1つのアクション呼び出しをテストしてください。成功した場合は、認証済みの呼び出しだけが機能するまで、プロキシで/api、/v1、/mcpをエージェントが使用するアドレスに制限してください。
Open Connectorは本番環境で使用できる状態ですか?
Apache 2.0ライセンスで提供され、開発も速いペースで進んでいます。リポジトリは2026年6月29日に公開され、v1.3.3は2026年7月30日にリリースされました。そのため、このガイドに記載されている各バージョン番号は2026年8月1日時点のスナップショットとして扱ってください。リリースタグを固定して実行し、latestやtipでは決して実行しないでください。アップグレード前に毎回リリースノートを確認し、一度リストアしたことのあるvolume backupを保持してください。自分で管理するサーバーであれば設計は堅実です。リスクはアーキテクチャではなく、バージョンの頻繁な変化にあります。