SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-26

AIエージェント向けOpen Connectorをセルフホストする方法

Open Connectorを自分のVPSで運用し、SaaS tokenをエージェントに渡さない構成を解説します。pinned image、TLS origin、OAuth callback、SQLite backupまで確認できます。

AI エージェントに対して Open Connector が行うこと

Open Connector をセルフホストすると、AI エージェントと、エージェントが呼び出すすべての software as a service (SaaS) API の間に、1 つの認証ゲートウェイを配置できます。エージェントがプロバイダーのトークンを保持する必要はありません。これは OOMOL Lab が提供する Apache 2.0 ライセンスのオープンソースゲートウェイです。1 つのコンテナとして動作し、状態を単一の SQLite ファイルに保存し、プロバイダーのアクションを HTTP と MCP (model context protocol) で公開します。

問題は、2 つ目の統合から始まります。プロバイダーごとに OAuth (open authorization) フロー、refresh token の有効期間、scope 名が異なります。5 つのプロバイダーをエージェントへ手動で接続するには、5 つの redirect handler、5 つの credential store、さらにトークンの期限切れ前に実行する 5 つの refresh loop が必要です。このコードを作成する人はほとんどいません。そのため、サービスごとに有効期間の長い personal access token を 1 つ発行し、エージェントの設定、環境ファイル、またはプロンプト自体に貼り付けます。そのトークンはエージェントが実行するすべての tool から読み取れる状態になり、transcript にも記録されます。これは、AI エージェントから秘密情報を除外する方法 が説明する問題です。

認証ゲートウェイは、credential を 2 つに分離します。ゲートウェイがプロバイダーの credential を保存し、OAuth フローを実行します。エージェントが受け取るのは、ゲートウェイに対してのみ有効な runtime token です。エージェントが action を呼び出すと、ゲートウェイは保存済みの credential を読み込み、サーバー側で outbound request に注入し、response body だけを返します。エージェントがプロバイダーの access token を受け取ることはありません。そのため、エージェントの transcript が漏洩しても、失うのは GitHub アカウントではなく、失効可能な runtime token 1 つで済みます。

カタログには 1,000 を超えるプロバイダーと 10,000 の prebuilt action が掲載されています。これはプロジェクトが示す数値であり、外部から検証できるものではありません。検証できるのは、その構成です。各 action に 1 つの HTTP endpoint、各プロバイダーに 1 つの保存済み connection、各エージェントに 1 つの token があります。エージェント側の仕組みがまだ新しく、tool call や MCP server などの用語も定着していない場合は、AI エージェントをゼロから学ぶ方法 の段階的な手順が、このようなゲートウェイを利用するために必要な loop、tool、安全な運用習慣を順に身につける助けになります。

ホスト型コネクターサービスではなく Open Connector を自己ホストする理由

ホスト型コネクターサービスも同じ処理を行いますが、接続するすべてのプロバイダーの refresh token を保持します。Google や GitHub の refresh token は、メールやリポジトリへの長期有効な暗号鍵であり、通常はパスワードを変更しても有効です。ホスト型サービスが侵害されると、あなたの環境も侵害されます。自己ホストにすると、これらの記録を自分が借りて管理するマシン上の SQLite に移し、マシンの外へ出ない鍵で保護できます。

開始する前に、コストを明確にしてください。この VPS は、運用する中で最も価値の高いサーバーになります。1 つのファイルに多数のサービスの有効な認証情報を保持するため、パスワードマネージャーをホストするサーバーと同じ扱いが必要です。具体的には、443 だけを公開するファイアウォール、共有ログインの禁止、実際に 1 回はリストアしたバックアップ、応答が停止したときのアラートを用意します。このサーバーにパスワード保管庫を置けないなら、コネクターも置かないでください。

インストールする前にバージョンを固定する

Open Connector は新しいプロジェクトです。リポジトリが最初に登場したのは 29 June 2026 です。2026 年 1 August 時点で、最新のタグ付きリリースは v1.3.3 です。このリリースは 30 July 2026 に公開され、latest タグも付いています。レジストリには tip タグも公開されています。このタグは main の最新コミットからビルドされています。

これほど新しいプロジェクトでは、可変タグが頻繁に更新されます。2 つ先のリリースへ移動する docker compose pull によって、エージェントが依存するエンドポイントが変更される可能性があります。その結果、原因をエージェントの問題だと考えて、夜までデバッグすることになります。イメージはリリースタグに固定してください。リリースノートを確認してから、必要なタイミングでアップグレードします。

TLS 終端の背後で、自分の VPS に Open Connector をデプロイする

コンテナを起動する前に、次を準備します。

  • Ubuntu 24.04 またはそれに近い環境の、Compose プラグイン付き Docker
  • A レコードがこの VPS を指すホスト名(例: connect.example.com
  • そのホスト名の TLS(transport layer security)をすでに終端しているリバースプロキシ
  • 以下で生成する2つのランダムな Secret

複数の Docker Compose アプリケーション用 Traefik リバースプロキシでは、プロキシ側の設定を説明しています。単一アプリケーションの証明書処理を最初から最後まで確認する場合は、Docker と HTTPS を使って VPS で n8n を運用するガイドを参照してください。

まず Secret を生成します。暗号化キーは保存済みの認証情報を保護します。管理者トークンは 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 と記述すると loopback インターフェースだけで公開され、リバースプロキシは同じホストから接続できます。

:? は各変数を必須として扱います。そのため、.env がない場合、認証情報を暗号化しないまま起動せず、スタックの起動を拒否します。値を compose ファイルではなく .env に保持する方法は、Docker Compose の env ファイルと Secretで説明しているパターンです。

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 } を返します。ss127.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 の静的設定にある resolver 名と一致させる必要があります。一致しない場合、ルーターは証明書なしで起動します。

OAuth で実在するホスト名が必要になる理由

OOMOL_CONNECT_ORIGIN は省略されがちな設定です。省略すると、プロバイダーの不具合に見える形で OAuth が失敗します。ランタイムは、このオリジンから <origin>/oauth/callback の形式でリダイレクト URI を組み立てます。オリジンが未設定の場合、デフォルト値は 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"

この一覧には、各プロバイダーについてランタイムが想定する redirect 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 を使用するプロバイダーでは、これらの手順は不要です。{"authType":"api_key","values":{"apiKey":"..."}} を指定した PUT /api/connections/<service> で、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_actionsexecute_action などの検出用ツールを提供するため、エージェントのツール一覧を小さく保てます。VPS で MCP サーバーを実行するでは、この接続のクライアント側を説明しています。

完了と判断する前に、もう1つ確認します。authorization ヘッダーを削除して、アクション呼び出しをもう一度実行してください。プロジェクト自身のクイックスタートでは、bearer なしで /v1 を呼び出しています。そのため、ランタイム認証を設定していないインストールでは、ポートに到達できる人なら誰でもアクションを実行できます。認証なしの呼び出しが成功した場合は、2つの対処方法があります。ランタイムトークンを設定し、匿名の呼び出しが失敗することを確認する方法です。もう1つは、リバースプロキシで /api/v1/mcp へのアクセスをエージェントの送信元アドレスに制限する方法です。世界中に公開したままにする必要があるのは /oauth/callback だけです。プロバイダーのブラウザーリダイレクトが必要とする経路はこれだけだからです。

エージェントに必要な操作だけにアクションリストを絞る

背後に 1000 個のプロバイダーがあるゲートウェイを、そのまま言語モデルに渡すと、操作可能な範囲が広すぎます。モデルが自分で書いていないテキストを読み始めると、さらに危険です。エージェントの Web 検索に応答する独自の SearXNG インスタンスが返すページには、エージェントが実行できる操作を狙った指示が含まれている可能性があります。コーディングエージェントに動作する最小限の変更だけを行わせるのと同じ制限を、権限にも適用します。実際の作業に必要な少数の操作だけを許可し、それ以外は許可しません。範囲を絞る設定は 2 つあります。

OOMOL_CONNECT_ALLOWED_ACTIONS にはカンマ区切りの許可リストを指定でき、service.** に対応しています。OOMOL_CONNECT_BLOCKED_ACTIONS は拒否リストで、拒否リストが優先されます。許可リストを github.get_current_user,github.list_issues に設定すると、エージェントが要求しても、それ以外のすべての操作が拒否されます。これは単なるミスとインシデントを分ける設定です。実行時トークンには、グローバル設定に加えて独自のアクションルールがあります。トークンの allowedProxies リストは空の状態で始まるため、POST /v1/proxy/:service は許可するまで拒否されます。このプロキシエンドポイントは、認証情報を付加してプロバイダーへ raw リクエストを転送します。そのため、特定のエージェントが必要とする場合を除き、空のままにしてください。

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 件保持します。そのため、コンソールで、どの agent が何をいつ実行したかを確認できます。agent の動作が不自然なときは、まずこのログを確認してください。Uptime Kuma のステータスページから https://connect.example.com/health も監視してください。gateway が応答しなくなると、agent は分かりにくい形で失敗します。gateway が停止していると分かれば、agent の出力を 1 時間読み続けずに済みます。

障害発生時の症状と表示されるメッセージ

redirect_uri_mismatch がプロバイダーで発生する。 オリジンと登録済みのコールバック URL が一致していません。/api/oauth/configs の正確な文字列をプロバイダーのアプリ設定と比較します。httpshttp の組み合わせや末尾のスラッシュも確認してください。

すべての /api 呼び出しが 401 を返す。 管理者トークンのヘッダーがないか、スペルが誤っています。ヘッダーは Authorization: Bearer <token> です。Web コンソールでも同じトークンを指定します。

コンテナは稼働しているが、認証情報が平文で保存されている。 これは OOMOL_CONNECT_ENCRYPTION_KEY がコンテナに渡っていない場合に発生します。ランタイムは起動を拒否せず、認証情報のレコードを暗号化しないまま保存します。自分の環境で確認してください。認識できる API key を使ってプロバイダーを接続し、その API key をデータベース内で検索します。

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

0 より大きい値は、key が適用されていないことを示します。.envcompose.yaml と同じディレクトリにあることと、docker compose config に値が表示されることを確認してください。key を設定すると、同じ検索結果は 0 になります。レコードが AES-256-GCM(advanced encryption standard、256-bit key、Galois/counter mode)で暗号化されるためです。

復元後に何も復号できない。 encryption key が変更されたか、失われています。設計上、key がデータの隣に書き込まれることはありません。そのため復旧手段はなく、サポートチケットでも解決できません。すべてのプロバイダーを再接続してください。ローテーションには、別の key 変数とランタイム内のデータコマンドを使用します。実行前に、現在のリリースノートを確認してください。

エージェントが、カタログに表示されている action の名前を含むエラーを返す。 検出と実行は別の処理です。action は search_actions に表示されていても、OOMOL_CONNECT_ALLOWED_ACTIONS、denylist、またはその runtime token 自体のルールによって拒否される場合があります。

アップグレード。 volume をバックアップし、image tag を新しいリリースに変更してから docker compose pull && docker compose up -d を実行します。docker compose logs -n 50 connector を監視し、migration の行が出力されることを確認してください。その後、health check と実際の action を 1 つ再実行してから、再び信頼して使用します。ロールバックするには古い tag に戻します。tag を固定していた場合に限り、これで動作します。

FAQ

Open Connector をセルフホストする場合、パブリックドメインは必要ですか?

API key を使用するプロバイダーでは不要です。127.0.0.1 上の gateway で十分です。OAuth では、実際には必要です。プロバイダーはブラウザーを callback URL にリダイレクトするため、その URL はパブリックインターネットから解決できなければなりません。また、プロバイダーは localhost 以外で通常の http:// を拒否します。初回起動前に OOMOL_CONNECT_ORIGINhttps:// hostname に設定し、プロバイダーの OAuth app に <origin>/oauth/callback を登録します。

Open Connector の encryption key を失うとどうなりますか?

保存された認証情報を復号できなくなり、復旧方法はありません。key は意図的にデータと同じ場所へ保存されないため、database を保持している人は誰も、あなた自身も含めて、それを読み取れません。唯一の方法は、新しい key を設定し、すべてのプロバイダーを再接続することです。key は password manager に保管し、database はバックアップのローテーションに含めてください。復元には両方が必要です。

AI agent はプロバイダーの access token を確認できますか?

gateway 経由で呼び出す場合は確認できません。agent は oct_ で始まる runtime token で認証し、gateway がサーバー上でプロバイダーの credential を outbound request に注入して、response だけを返します。この特性を損なうのは2つです。1つ目は /v1/proxy/:service endpoint です。これは credential を付けた raw request を転送します。grant が空のままなのには理由があります。2つ目は、あなた自身が agent に API key を貼り付けることです。この場合、gateway を完全に経由しません。

gateway はパブリックインターネットから到達可能にすべきですか?

到達可能にする必要があるのは /oauth/callback だけです。127.0.0.1 で container port を公開し、Docker の NAT ルールが firewall の外側へ公開できないようにして、前段に reverse proxy を置きます。その後、authorization header なしで1つの action call をテストします。成功した場合は、認証済みの call だけが機能する状態になるまで、proxy で /api/v1/mcp を agent が使用するアドレスに制限します。

Open Connector は本番運用に対応していますか?

Apache 2.0 licensed で、開発も速いペースで進んでいます。repository は 29 June 2026 に公開され、v1.3.3 は 30 July 2026 にリリースされたため、このガイドの各 version number は 1 August 2026 時点のスナップショットとして扱ってください。release tag を固定して実行し、latesttip では決して実行しないでください。各 upgrade の前に release notes を読み、1度復元したことのある volume backup を保持します。自分で管理するサーバーであれば設計は堅実です。リスクは architecture ではなく、version の変動です。