OpenCode の認証設定の追加 #3

Open
opened 2026-08-18 18:45:21 +09:00 by genji1024 · 8 comments
Owner

現在は /opencode で OpenCode Web UI 画面が表示されるが、チャットができない。エンドポイントや API トークンを設定し、Web UI からチャットができるようにする。

現在は `/opencode` で OpenCode Web UI 画面が表示されるが、チャットができない。エンドポイントや API トークンを設定し、Web UI からチャットができるようにする。
Author
Owner

@bot-genji1024 実装方針を立ててください。

@bot-genji1024 実装方針を立ててください。
Collaborator

@genji1024 実装方針を提示します。

実装方針: OpenCode の認証設定の追加(Web UI からチャット可能にする)

1. 現状把握

  • アプリ(Next.js, port 3001)は /opencode で OpenCode Web UI を表示。
  • サーバー側で opencode serve --hostname 0.0.0.0 --port 4096 が稼働(Docker サービス opencode-srv)。
  • アプリ内プロキシ src/app/opencode-proxy/[[...path]]/route.ts が OPENCODE_SERVER_URL(既定 http://127.0.0.1:4096)へ転送し、fetch/EventSource のパスを書き換え。
  • アプリ自体には Basic Auth(src/middleware.ts / src/lib/auth.ts / src/app/api/auth/route.ts)あり。
  • コンテナ起動時に docker-entrypoint-opencode.sh が auth.json + opencode.jsonc を動的生成し、STREAMABLE_HTTP_AUTH_TOKEN 等を設定。
  • 現在「画面は出るがチャットができない」=ブラウザの Web UI クライアントが opencode-srv のエンドポイントとトークンで接続できていない状態。

2. 原因の切り分け(想定される主因)

  1. エンドポイント未設定/不一致: Web UI クライアントが opencode-srv の HTTP エンドポイント(Streamable HTTP)を正しく指していない。ブラウザからは 127.0.0.1:4096 に直接到達できないため、プロキシ経由のパスをクライアント設定に反映する必要がある。
  2. API トークン未設定/未転送: STREAMABLE_HTTP_AUTH_TOKEN による Bearer 認証が opencode-srv 側で有効な場合、クライアントがトークンを送る必要がある。またプロキシが Authorization ヘッダを opencode-srv へ転送できているか確認が必要。
  3. プロキシのパス書き換え漏れ: チャットのストリーム(fetch/EventSource)以外の通信がある場合、そのパスの書き換え・転送が漏れている可能性。

3. 実装方針(ステップ)

  • Step 1: エンドポイント設定 — Web UI クライアントが参照するサーバー URL を、ブラウザから到達可能なプロキシ経由パス(例: /opencode-proxy)に統一する。opencode-proxy の INJECT_SCRIPT 等の注入箇所を見直し、エンドポイントを正しく注入する。
  • Step 2: API トークンの設定と転送 — STREAMABLE_HTTP_AUTH_TOKEN(または OPENCODE_SERVER_PASSWORD)を明示的に設定し、クライアントが Bearer トークンとして送信できるようにする。プロキシが Authorization ヘッダを opencode-srv へ透過転送することを確認・実装する。
  • Step 3: プロキシのパス書き換え・転送の網羅 — チャットに必要な全エンドポイント(ストリーム系)がプロキシで正しく書き換え・転送されることを確認する。
  • Step 4: 設定の集約と環境変数 — .env.example / .env に認証関連変数(エンドポイント URL・トークン)を追加し、docker-entrypoint-opencode.sh の生成設定と整合させる。

4. 変更候補ファイル

  • src/app/opencode-proxy/[[...path]]/route.ts — エンドポイント / トークン / ヘッダ転送
  • docker-entrypoint-opencode.sh — opencode.jsonc / auth.json 生成(認証設定)
  • .env.example / .env — 認証関連環境変数の追加
  • (必要に応じ)src/lib/opencode-serve.ts — サーバー起動・ヘルスチェック

5. 検証手順(受け入れ基準)

  • docker compose up で2サービス(app / opencode-srv)が起動する
  • ブラウザで /opencode を開き Basic Auth でログインできる
  • Web UI 上でメッセージを送信し、チャット応答が返る(ストリーム含む)
  • lint / typecheck / build が通る
  • トークンがログ・HTML・クライアントに平文露出しない

6. 確認事項(実装着手時に要確認)

  • OpenCode クライアントのエンドポイント・認証指定方法(opencode のバージョン 1.18.9 の仕様)を実物で確認してから設定値を確定する。
  • STREAMABLE_HTTP_AUTH_TOKEN と OPENCODE_SERVER_PASSWORD の使い分けを現行実装で確認する。

この方針で問題なければ Step 1〜4 を実装に移ります。実装着手の承認、または方針への修正指示をお待ちします。

@genji1024 実装方針を提示します。 ## 実装方針: OpenCode の認証設定の追加(Web UI からチャット可能にする) ### 1. 現状把握 - アプリ(Next.js, port 3001)は `/opencode` で OpenCode Web UI を表示。 - サーバー側で `opencode serve --hostname 0.0.0.0 --port 4096` が稼働(Docker サービス opencode-srv)。 - アプリ内プロキシ `src/app/opencode-proxy/[[...path]]/route.ts` が `OPENCODE_SERVER_URL`(既定 http://127.0.0.1:4096)へ転送し、fetch/EventSource のパスを書き換え。 - アプリ自体には Basic Auth(`src/middleware.ts` / `src/lib/auth.ts` / `src/app/api/auth/route.ts`)あり。 - コンテナ起動時に `docker-entrypoint-opencode.sh` が `auth.json` + `opencode.jsonc` を動的生成し、`STREAMABLE_HTTP_AUTH_TOKEN` 等を設定。 - 現在「画面は出るがチャットができない」=ブラウザの Web UI クライアントが opencode-srv のエンドポイントとトークンで接続できていない状態。 ### 2. 原因の切り分け(想定される主因) 1. エンドポイント未設定/不一致: Web UI クライアントが opencode-srv の HTTP エンドポイント(Streamable HTTP)を正しく指していない。ブラウザからは 127.0.0.1:4096 に直接到達できないため、プロキシ経由のパスをクライアント設定に反映する必要がある。 2. API トークン未設定/未転送: `STREAMABLE_HTTP_AUTH_TOKEN` による Bearer 認証が opencode-srv 側で有効な場合、クライアントがトークンを送る必要がある。またプロキシが `Authorization` ヘッダを opencode-srv へ転送できているか確認が必要。 3. プロキシのパス書き換え漏れ: チャットのストリーム(fetch/EventSource)以外の通信がある場合、そのパスの書き換え・転送が漏れている可能性。 ### 3. 実装方針(ステップ) - Step 1: エンドポイント設定 — Web UI クライアントが参照するサーバー URL を、ブラウザから到達可能なプロキシ経由パス(例: `/opencode-proxy`)に統一する。`opencode-proxy` の INJECT_SCRIPT 等の注入箇所を見直し、エンドポイントを正しく注入する。 - Step 2: API トークンの設定と転送 — `STREAMABLE_HTTP_AUTH_TOKEN`(または `OPENCODE_SERVER_PASSWORD`)を明示的に設定し、クライアントが Bearer トークンとして送信できるようにする。プロキシが `Authorization` ヘッダを opencode-srv へ透過転送することを確認・実装する。 - Step 3: プロキシのパス書き換え・転送の網羅 — チャットに必要な全エンドポイント(ストリーム系)がプロキシで正しく書き換え・転送されることを確認する。 - Step 4: 設定の集約と環境変数 — `.env.example` / `.env` に認証関連変数(エンドポイント URL・トークン)を追加し、`docker-entrypoint-opencode.sh` の生成設定と整合させる。 ### 4. 変更候補ファイル - `src/app/opencode-proxy/[[...path]]/route.ts` — エンドポイント / トークン / ヘッダ転送 - `docker-entrypoint-opencode.sh` — opencode.jsonc / auth.json 生成(認証設定) - `.env.example` / `.env` — 認証関連環境変数の追加 - (必要に応じ)`src/lib/opencode-serve.ts` — サーバー起動・ヘルスチェック ### 5. 検証手順(受け入れ基準) - [ ] `docker compose up` で2サービス(app / opencode-srv)が起動する - [ ] ブラウザで `/opencode` を開き Basic Auth でログインできる - [ ] Web UI 上でメッセージを送信し、チャット応答が返る(ストリーム含む) - [ ] lint / typecheck / build が通る - [ ] トークンがログ・HTML・クライアントに平文露出しない ### 6. 確認事項(実装着手時に要確認) - OpenCode クライアントのエンドポイント・認証指定方法(`opencode` のバージョン 1.18.9 の仕様)を実物で確認してから設定値を確定する。 - `STREAMABLE_HTTP_AUTH_TOKEN` と `OPENCODE_SERVER_PASSWORD` の使い分けを現行実装で確認する。 この方針で問題なければ Step 1〜4 を実装に移ります。実装着手の承認、または方針への修正指示をお待ちします。
Author
Owner

@bot-genji1024 すみません。私が「エンドポイントや API トークン」と書いたのは、OpenCode サーバがアクセスする LLM エンドポイントとそのアクセストークンを意図していました。個人的に OpenCode Go を契約しているので、そのエンドポイントと API キーをブラウザから入力することで認証できるようにしたいです。これを踏まえて、再度方針を立ててください。

@bot-genji1024 すみません。私が「エンドポイントや API トークン」と書いたのは、OpenCode サーバがアクセスする LLM エンドポイントとそのアクセストークンを意図していました。個人的に OpenCode Go を契約しているので、そのエンドポイントと API キーをブラウザから入力することで認証できるようにしたいです。これを踏まえて、再度方針を立ててください。
Collaborator

@genji1024 要件を訂正いただきありがとうございます。ご指摘の通り、前回(#89)は「エンドポイント/APIトークン」を Web UI ↔ opencode-srv 間の接続設定と誤解していました。正しくは「OpenCode サーバがアクセスする LLM エンドポイント(OpenCode Go)とその API キーをブラウザから入力して認証する」という理解で、方針を立て直します。

要件の理解(確認)

  • ブラウザ(管理ダッシュボード)から LLM エンドポイント(baseURL) と API キー を入力
  • 入力値がサーバ側の OpenCode 設定(auth.json の opencode-go プロバイダ等)に反映され、OpenCode サーバが OpenCode Go へ認証付きでアクセス
  • 結果として /opencode の Web UI からチャットできる

現状の整理

  • OPENCODE_API_KEY は docker-entrypoint-opencode.sh で ~/.local/share/opencode/auth.json の "opencode-go": {"type":"api","key":...} に書き込まれている
  • baseURL(エンドポイント)の設定箇所はリポジトリ内に存在しない(現状は OpenCode CLI のデフォルト依存)
  • 設定保存は SQLite configs テーブル + src/lib/store.ts の getConfig/setConfig、API は PUT /api/config/[key]
  • 設定画面 src/app/settings/page.tsx に接続テストの先例(test-github-token)あり

実装方針(案)

  1. 設定入力 UI: src/app/settings/page.tsx に「LLM エンドポイント」「LLM API キー」の入力欄を追加(API キーは password 型・マスク表示、既存の表示トグルを踏襲)
  2. 保存: 既存の CONFIG_KEYS に llm_endpoint / llm_api_key を追加し、PUT /api/config/[key] → store.setConfig → SQLite に保存(スキーマ変更不要)
  3. OpenCode への反映(設計の核心。運用が Docker 別コンテナのため):
    • 保存値を opencode-srv コンテナへ反映する手段として、(a) Next.js 側 API から auth.json を書き換えて opencode-srv を再起動、または (b) 保存値を docker-compose の env に書き出して再起動、のいずれかを採用
    • auth.json の opencode-go に key を、エンドポイントは OpenCode 1.18.9 の baseURL 指定方法(auth.json のプロバイダ定義 or opencode.json の設定)を実装時に確定して設定
  4. 接続テスト: test-github-token を流用し「LLM 接続テスト」API を追加(エンドポイント+キーで疎通確認し、結果を設定画面に表示)
  5. セキュリティ: 保存済み API キーは平文表示を避け、.env に実値で存在する OPENCODE_API_KEY の扱い(削除 or ブラウザ入力値への一本化)も方針に含める
  6. 既存問題の解消: opencode_model 等「保存はされるが利用されない」デッドキー問題をこの機会に整理(LLM 設定を実際の OpenCode 起動に使う経路を一本化)

確認事項(実装着手前に確定したい点)

  • OpenCode 1.18.9 における baseURL の指定方法(auth.json / opencode.json のどちらか)をリポジトリ・バイナリの仕様で確認
  • 反映方式 (a)/(b) のどちらを採用するか(Docker 運用前提なら (b) がシンプルかと想定)

次のステップ

方針をご確認いただき、問題なければこの方針で実装に着手します(実装 PR を作成します)。

@genji1024 要件を訂正いただきありがとうございます。ご指摘の通り、前回(#89)は「エンドポイント/APIトークン」を Web UI ↔ opencode-srv 間の接続設定と誤解していました。正しくは「OpenCode サーバがアクセスする LLM エンドポイント(OpenCode Go)とその API キーをブラウザから入力して認証する」という理解で、方針を立て直します。 ## 要件の理解(確認) - ブラウザ(管理ダッシュボード)から **LLM エンドポイント(baseURL)** と **API キー** を入力 - 入力値がサーバ側の OpenCode 設定(`auth.json` の `opencode-go` プロバイダ等)に反映され、OpenCode サーバが OpenCode Go へ認証付きでアクセス - 結果として `/opencode` の Web UI からチャットできる ## 現状の整理 - `OPENCODE_API_KEY` は `docker-entrypoint-opencode.sh` で `~/.local/share/opencode/auth.json` の `"opencode-go": {"type":"api","key":...}` に書き込まれている - **baseURL(エンドポイント)の設定箇所はリポジトリ内に存在しない**(現状は OpenCode CLI のデフォルト依存) - 設定保存は SQLite `configs` テーブル + `src/lib/store.ts` の getConfig/setConfig、API は `PUT /api/config/[key]` - 設定画面 `src/app/settings/page.tsx` に接続テストの先例(`test-github-token`)あり ## 実装方針(案) 1. **設定入力 UI**: `src/app/settings/page.tsx` に「LLM エンドポイント」「LLM API キー」の入力欄を追加(API キーは password 型・マスク表示、既存の表示トグルを踏襲) 2. **保存**: 既存の `CONFIG_KEYS` に `llm_endpoint` / `llm_api_key` を追加し、`PUT /api/config/[key]` → `store.setConfig` → SQLite に保存(スキーマ変更不要) 3. **OpenCode への反映**(設計の核心。運用が Docker 別コンテナのため): - 保存値を `opencode-srv` コンテナへ反映する手段として、(a) Next.js 側 API から `auth.json` を書き換えて opencode-srv を再起動、または (b) 保存値を docker-compose の env に書き出して再起動、のいずれかを採用 - `auth.json` の `opencode-go` に `key` を、エンドポイントは OpenCode 1.18.9 の baseURL 指定方法(auth.json のプロバイダ定義 or opencode.json の設定)を**実装時に確定**して設定 4. **接続テスト**: `test-github-token` を流用し「LLM 接続テスト」API を追加(エンドポイント+キーで疎通確認し、結果を設定画面に表示) 5. **セキュリティ**: 保存済み API キーは平文表示を避け、`.env` に実値で存在する `OPENCODE_API_KEY` の扱い(削除 or ブラウザ入力値への一本化)も方針に含める 6. **既存問題の解消**: `opencode_model` 等「保存はされるが利用されない」デッドキー問題をこの機会に整理(LLM 設定を実際の OpenCode 起動に使う経路を一本化) ## 確認事項(実装着手前に確定したい点) - OpenCode 1.18.9 における **baseURL の指定方法**(auth.json / opencode.json のどちらか)をリポジトリ・バイナリの仕様で確認 - 反映方式 (a)/(b) のどちらを採用するか(Docker 運用前提なら (b) がシンプルかと想定) ## 次のステップ 方針をご確認いただき、問題なければこの方針で実装に着手します(実装 PR を作成します)。
Author
Owner

@bot-genji1024 方針は概ね問題ないと思います。反映方式 (a) と (b) の違いを詳しく説明していただけますか?

@bot-genji1024 方針は概ね問題ないと思います。反映方式 (a) と (b) の違いを詳しく説明していただけますか?
Collaborator

@genji1024 反映方式 (a) と (b) の違いを、このリポジトリの実際の構成に即して説明します。

前提(現状の仕組み)

  • opencode-srv は docker-compose のサービスで、docker-entrypoint-opencode.sh がコンテナ起動のたびに OPENCODE_API_KEY から ~/.local/share/opencode/auth.json を再生成します(chmod 600)。MCP 設定の opencode.jsonc も同様に環境変数から起動時に生成されます。
  • opencode はこれらを起動時に読み込むため、実行中の変更は反映されません(反映には再起動が必要)。
  • 設定画面で保存した値は Next.js 側の SQLite configs テーブル(PUT /api/config/[key])に入るだけで、opencode-srv コンテナには伝わりません。
  • opencode-srv にはボリュームマウントがありません(コンテナは再作成前提の使い捨て)。

つまり「保存値を opencode-srv に反映する」とは、「auth.json(と baseURL)を更新し、opencode-srv を再起動する」ことを意味します。

(a) auth.json を直接書き換えて再起動

Next.js 側(API ルート)から opencode-srv コンテナ内の ~/.local/share/opencode/auth.json を直接編集し、opencode-srv を再起動する方式です。

  • 長所: 環境変数を介さず保存値をファイルへ直接反映できる。baseURL とキーを同じ場所に書ける。
  • 短所:
    1. 起動時に上書きされる: OPENCODE_API_KEY が compose の env に残る限り、再作成時に entrypoint が auth.json を再生成して書き換えが消えます。永続化するには compose 側の OPENCODE_API_KEY を外す必要があり、すると「ファイルが唯一の真実」になります。
    2. ボリュームがないため再作成で消失: docker compose up -d(deploy.sh)でコンテナが再作成されると、コンテナ層に書いたファイルは消えます。「再作成後に再書き込み」という順序管理が必要で壊れやすいです。
    3. コンテナ越しの書き込み手段が必要: Next.js コンテナから opencode-srv コンテナのファイルシステムへ書き込むには、共有ボリュームや Docker ソケットの共有が必要で、現構成にはありません。

(b) docker-compose の env に書き出して再起動

保存値をリポジトリ直下の .env に書き込み、docker compose up -d で再起動する方式です。

  • 長所:
    1. 既存の仕組みに乗る: 現状すでに .env → compose → entrypoint → auth.json/opencode.jsonc の経路が動作しており、これを使うのが自然です。baseURL も「新設の env(例 OPENCODE_LLM_BASE_URL)を entrypoint で設定ファイルに書き込む」形で同様に反映できます。
    2. 再作成に強い: env が唯一の真実なので、再作成・再起動しても設定が失われません。
    3. Next.js 側に特別な権限が不要: .env への書き込みと再起動トリガーだけで済みます(Docker ソケット共有は不要)。
  • 短所:
    1. 反映に再起動が必要(数秒のダウンタイム)。
    2. シークレットが .env に平文保存(ただし現状の OPENCODE_API_KEY も同じ場所・同じ扱いのため、リスクは増えません)。
    3. Next.js から .env への書き込み+再起動(既存 deploy.sh の流用 or 専用反映エンドポイント)の実装が必要。

推奨

Docker 運用前提のこの構成では (b) を推奨します。すでに「env → entrypoint → 設定ファイル」という再作成に強い経路が動いており、これに乗るのが最も壊れにくく、シークレット管理の一貫性も保てるためです。(a) はファイルを直接触る直感性はありますが、ボリュームなし・起動時再生成というこのリポジトリの特性と相性が悪く、再作成で設定が消える運用事故を招きやすいです。

(b) の方向で確定でよければ、具体的な変更箇所(.env の追加変数・entrypoint への書き込み追加・設定画面からの反映フロー)を整理して実装に進みます。ご確認をお願いします。

@genji1024 反映方式 (a) と (b) の違いを、このリポジトリの実際の構成に即して説明します。 ## 前提(現状の仕組み) - `opencode-srv` は docker-compose のサービスで、`docker-entrypoint-opencode.sh` が**コンテナ起動のたびに** `OPENCODE_API_KEY` から `~/.local/share/opencode/auth.json` を再生成します(chmod 600)。MCP 設定の `opencode.jsonc` も同様に環境変数から起動時に生成されます。 - opencode はこれらを**起動時**に読み込むため、実行中の変更は反映されません(反映には再起動が必要)。 - 設定画面で保存した値は Next.js 側の SQLite `configs` テーブル(`PUT /api/config/[key]`)に入るだけで、opencode-srv コンテナには伝わりません。 - `opencode-srv` には**ボリュームマウントがありません**(コンテナは再作成前提の使い捨て)。 つまり「保存値を opencode-srv に反映する」とは、「auth.json(と baseURL)を更新し、opencode-srv を再起動する」ことを意味します。 ## (a) auth.json を直接書き換えて再起動 Next.js 側(API ルート)から opencode-srv コンテナ内の `~/.local/share/opencode/auth.json` を直接編集し、opencode-srv を再起動する方式です。 - 長所: 環境変数を介さず保存値をファイルへ直接反映できる。baseURL とキーを同じ場所に書ける。 - 短所: 1. **起動時に上書きされる**: `OPENCODE_API_KEY` が compose の env に残る限り、再作成時に entrypoint が auth.json を再生成して書き換えが消えます。永続化するには compose 側の `OPENCODE_API_KEY` を外す必要があり、すると「ファイルが唯一の真実」になります。 2. **ボリュームがないため再作成で消失**: `docker compose up -d`(deploy.sh)でコンテナが再作成されると、コンテナ層に書いたファイルは消えます。「再作成後に再書き込み」という順序管理が必要で壊れやすいです。 3. **コンテナ越しの書き込み手段が必要**: Next.js コンテナから opencode-srv コンテナのファイルシステムへ書き込むには、共有ボリュームや Docker ソケットの共有が必要で、現構成にはありません。 ## (b) docker-compose の env に書き出して再起動 保存値をリポジトリ直下の `.env` に書き込み、`docker compose up -d` で再起動する方式です。 - 長所: 1. **既存の仕組みに乗る**: 現状すでに `.env` → compose → entrypoint → auth.json/opencode.jsonc の経路が動作しており、これを使うのが自然です。baseURL も「新設の env(例 `OPENCODE_LLM_BASE_URL`)を entrypoint で設定ファイルに書き込む」形で同様に反映できます。 2. **再作成に強い**: env が唯一の真実なので、再作成・再起動しても設定が失われません。 3. **Next.js 側に特別な権限が不要**: `.env` への書き込みと再起動トリガーだけで済みます(Docker ソケット共有は不要)。 - 短所: 1. **反映に再起動が必要**(数秒のダウンタイム)。 2. **シークレットが `.env` に平文保存**(ただし現状の `OPENCODE_API_KEY` も同じ場所・同じ扱いのため、リスクは増えません)。 3. Next.js から `.env` への書き込み+再起動(既存 `deploy.sh` の流用 or 専用反映エンドポイント)の実装が必要。 ## 推奨 Docker 運用前提のこの構成では **(b) を推奨**します。すでに「env → entrypoint → 設定ファイル」という再作成に強い経路が動いており、これに乗るのが最も壊れにくく、シークレット管理の一貫性も保てるためです。(a) はファイルを直接触る直感性はありますが、ボリュームなし・起動時再生成というこのリポジトリの特性と相性が悪く、再作成で設定が消える運用事故を招きやすいです。 (b) の方向で確定でよければ、具体的な変更箇所(`.env` の追加変数・entrypoint への書き込み追加・設定画面からの反映フロー)を整理して実装に進みます。ご確認をお願いします。
Author
Owner

@bot-genji1024 (b) でよいと思います。実装と PR 作成をお願いします。

@bot-genji1024 (b) でよいと思います。実装と PR 作成をお願いします。
Collaborator

@genji1024 ご指示のとおり (b) の実装を行い、PR #4 を作成しました。

  • PR: #4
  • 内容: LLM エンドポイント・API キーの設定機能(feat(settings): add LLM endpoint and API key configuration)
  • Docker 動作確認(docker-mcp 使用)も完了しています。
@genji1024 ご指示のとおり (b) の実装を行い、PR #4 を作成しました。 - PR: https://forgejo.genji1024.com/genji1024/private-opencode-server/pulls/4 - 内容: LLM エンドポイント・API キーの設定機能(feat(settings): add LLM endpoint and API key configuration) - Docker 動作確認(docker-mcp 使用)も完了しています。
Sign in to join this conversation.
No labels
enhancement
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
genji1024/private-opencode-server#3
No description provided.