関連オープンソースリポジトリ:本記事のワンコマンドデプロイ版です。Docker デプロイ、キー生成、設定レンダリングを一つのコマンドで完了し、クライアント設定生成スクリプトと Nginx サンプルも同梱しています:

kuangyongjie/cliproxyapi-codex-deploy

git clone https://github.com/kuangyongjie/cliproxyapi-codex-deploy.git
cd cliproxyapi-codex-deploy
./scripts/setup.sh

Codex を普段から使っていると、いずれ一つの疑問が出てきます。

公式へ直接ログインしたまま使うのか。それとも自分で proxy layer を用意し、Codex を自分の AI 開発環境の一部として扱うのか。

PC が一台、アカウントも一つで、ローカルで Codex を使うだけなら公式ログインが最も軽いです。サービスが一段少なく、保守も障害点も減ります。

ただ、次のような要件が出ると事情が変わります。

  • 複数マシンで毎回 OAuth をやり直したくない
  • Codex、Claude Code、Gemini CLI などの入口をまとめたい
  • OAuth state、access control、互換 API を一か所で管理したい
  • 複数アカウントや routing を後から追加したい
  • OpenAI-compatible な自前 endpoint を他のサービスでも使いたい

この段階では CLIProxyAPI のような proxy layer に意味が出てきます。

単なる request forwarding ではなく、上流の認証状態と下流のアクセスを分離する入口として使えるからです。

この構成で分けるべき三つの層

私が一番理解しやすかったのは、全体を三層に分けることでした。

  1. サーバー上の CLIProxyAPI
  2. proxy 側に保存される Codex OAuth state
  3. ローカル Codex の ~/.codex/config.toml と ~/.codex/auth.json

この三つを混ぜないことが大切です。

config.yaml は proxy service の設定。

auth/ は proxy が取得した OAuth state の保存先。

~/.codex/config.toml は手元の Codex client がどの provider / endpoint を使うかの設定です。

「proxy にログインすること」と「Codex client を proxy に向けること」は別の作業です。

サーバー側の最小ディレクトリ

私は最初から複雑な構成にせず、例えば次の程度にします。

/opt/cliproxyapi/
├── docker-compose.yml
├── config.yaml
└── auth/

auth/ は特に重要です。

CLIProxyAPI の auth-dir はデフォルトでは ~/.cli-proxy-api です。Docker で使うなら、この directory を host 側へ mount して、container を作り直しても OAuth state が消えないようにします。

「一度ログインできたのに container recreate 後に認証が消えた」という問題は、ここが永続化されていないケースが多いです。

config.yaml は最小から始める

最初から大量の設定を入れず、まず proxy service を安定して起動させます。

公式 config.example.yaml の中で、初期段階に見るのは例えばこの辺です。

host: ""
port: 8317
auth-dir: "~/.cli-proxy-api"

api-keys:
  - "<proxy-api-key>"

remote-management:
  allow-remote: false
  secret-key: ""

ここで重要なのは、api-keys が OpenAI の upstream key ではないことです。

これは下流クライアントが自分の proxy へアクセスするための keyです。

例えば、

  • Codex App 用
  • 別の self-hosted frontend 用
  • internal automation 用

と分けて発行できます。

後で一つの project だけ無効化したり、key rotation、rate limit、log separation をしたいとき、upstream OAuth を各 client へ配り直さずに済みます。

もう一つは remote-management.allow-remote です。

明確な理由がないなら最初は false のままにします。API を公開することと、management interface を公開することは別です。

Docker Compose

目的は単純です。

  • API port を出す
  • OAuth callback 用 port を出す
  • config と auth directory を mount する

例えば次のようにします。

services:
  cli-proxy-api:
    image: eceasy/cli-proxy-api:latest
    container_name: cli-proxy-api
    restart: unless-stopped
    ports:
      - "127.0.0.1:8317:8317"
      - "127.0.0.1:1455:1455"
    volumes:
      - ./config.yaml:/CLIProxyAPI/config.yaml
      - ./auth:/root/.cli-proxy-api

両方の port は意図的に loopback へ bind しています。API port は同一 host の Nginx から到達できれば十分ですし(後述の Client 側でも http://127.0.0.1:8317 へ proxy しています)、OAuth callback の listener は公開 publish すると全 interface に bind してしまう履歴が文書化されています(upstream issue #3463)。この二つの port をデフォルトで公開 internet へ出すと、一時的な login 面が恒久的なものに変わってしまうので、公開 publish を安全なデフォルトとして扱わないでください。network topology 上どうしても広い access が必要な場合は、起点としてではなく、独自の制限を付けた明示的な例外として定義してください。

image tag についてもう一点。:latest は可変 tag です。本ガイドの v8 field map は upstream repository の main branch(2026-10-14 確認)に対して検証したもので、この image を実行して検証したわけではありません。deploy 前に pull する tag がその layout と一致していることを確認するか、自分で検証した digest を固定してください。

1455 は通常の API traffic 用ではありません。

CLIProxyAPI の Codex OAuth callback で使われる port です。

API port 8317 だけを見ていると、service 自体は起動しているのに --codex-login の callback が戻ってこない、という状態になりやすいです。

まず proxy 自身に Codex OAuth を持たせる

Compose が起動した後、まだローカル Codex の設定は変えません。

先に CLIProxyAPI が Codex OAuth state を取得できることを確認します。

公式の流れでは次のような command を使います。

docker compose exec cli-proxy-api /CLIProxyAPI/CLIProxyAPI -no-browser --codex-login

remote Linux server では -no-browser が扱いやすいです。

container 内で browser を起動しようとせず、認証 URL を表示するので、その URL を手元の browser で開いて OAuth を完了できます。

この callback で remote machine 上で間違えやすい点が一つあります。browser は手元の laptop で動くので、http://localhost:1455/auth/callback は container の port mapping に関わらず laptop 自身を指します — VPS ではありません。remote Linux / VPS 構成で loop を閉じる順序は次です。

  1. 手元のマシン(server ではなく)で先に tunnel を開きます。
    ssh -N -L 1455:127.0.0.1:1455 <user>@<vps>
  2. 本ガイドの login command を実行します。CLI は OAuth URL を出力します(-no-browser では CLI 自身がこの SSH tunnel 手順を出力します)。
  3. 手元の browser でその URL を開き、sign-in を完了します。localhost:1455 への callback は tunnel 経由で container に戻ります。

tunnel を省略すると、CLI は “Waiting for Codex authentication callback…” で止まり、約 15 秒後に Paste the Codex callback URL (or press Enter to keep waiting): と促してきます。browser の address bar から callback URL 全文を貼り付ければ fallback できます — これは CLI 自身の manual path で、裏技ではありません。

ここで覚えておきたいのは、ログインしているのはローカル Codex App ではなく proxy service だということです。

認証が成功したら、mount した auth/ directory に state が保存されることを確認します。

私はまず次を見ます。

  • docker compose logs -f
  • host 側の auth/ に新しいファイルができたか

この段階が通っていなければ、ローカル config.toml をいくら変更しても意味がありません。

config.yaml フィールドリファレンス(v8)

本ガイド前半の最小 config.yaml は旧来の top-level 記述(host、port、auth-dir、api-keys、remote-management)を使っています。これらも問題なく読み込まれますが、upstream project は v8 layout(config-version: 8)へ移行し、すべての設定が名前付き section の下に収まるようになりました。upstream repository の現行 config.example.yaml から例を写すと新 layout になりますので、Codex proxy 構成で実際に触れる設定の field 対応表を置きます。各 field 名は upstream config.example.yaml の main branch に対して検証済みです(2026-10-14 確認)。Plus fork は乖離する可能性があります。適用前に pin した image / version と config.example.yaml を確認してください。

フィールド(v8)旧記述内容
config-version: 8—v8 layout の宣言。新旧両方の記述がある場合、v8 の値が優先されます。
server.hosthostbind する interface。空文字は全 interface に bind します。
server.portportclient が呼ぶ API port。本ガイドでは 8317。
oauth.auth-dirauth-dirCodex OAuth state の保存先。auth/ の mount と一致させないと restart で login が消えます。
access.api-keysapi-keys下流 client に渡す key。upstream の OpenAI credential ではありません。
management.allow-remoteremote-management.allow-remotemanagement API を公開する明確な理由がなければ false のままにします。
management.secret-keyremote-management.secret-keymanagement API の key。空にすると management API 自体が無効になります。
client.codex.optimize-multi-agent-v2—任意。Codex Desktop / codex-tui の multi-agent 構成向け最適化。デフォルト false。

本ガイドの構成向け v8 スタイル最小設定は次のようになります。

config-version: 8

server:
  host: ""
  port: 8317

oauth:
  auth-dir: "~/.cli-proxy-api"

access:
  api-keys:
    - "<proxy-api-key>"

management:
  allow-remote: false
  secret-key: ""

二点だけ補足します。第一に、access.api-keys は旧来の api-keys と同じ list です。下流 client に渡す key であり、upstream secret ではありません。第二に、container 内の oauth.auth-dir はデフォルトで /root/.cli-proxy-api に解決されるため、compose で ./auth をそこへ mount しています。片方だけ変えると、前節の「昨日動いていたのに restart で login が消えた」が戻ってきます。

Docker Compose: スタンドアロン構成

本ガイド冒頭の companion repo は、以下すべてを一つの script に自動化しています。各ファイルを自分で所有し、何が実行されるか正確に把握したい場合は、同じ構成の standalone compose project がこちらです。helper script は使いません。

同じ小さな directory を保ちます。

/opt/cliproxyapi/
├── docker-compose.yml
├── config.yaml
└── auth/

compose file は上記 Server 側 section と同じものです。同じ 127.0.0.1 bind の port、同じ mount を、upstream repository 自身の docker-compose.yml から組み立て、本ガイドに必要な分だけに絞っています。正しく保つべき file は一つにすべきなので、ここでは繰り返しません。上から写してください。./auth の mount は oauth.auth-dir の指す先に着地させ続けないと、container 再構築のたびに OAuth state が失われます。

起動して様子を見ます。

docker compose config
docker compose up -d
docker compose logs -f

最初の一行は習慣にする価値があります。docker compose config は何も起動せずに有効な file を描画します。indent ミスや mount path の誤りを runtime の謎になる前に捉える、無料の静的 check です。

次に前節と同様に Codex login を実行します。

docker compose exec cli-proxy-api /CLIProxyAPI/CLIProxyAPI -no-browser --codex-login

正直な注意点として、上記 compose file の各 field は upstream repository の docker-compose.yml および本ガイド既出の設定に対して検証済みですが、今回の更新ではこの file そのものを実機で実行していません。環境が異なる場合(rootless Docker、非標準の data root など)、volume path が最初に確認すべき箇所です。

ローカル Codex を自分の provider へ向ける

proxy 側の OAuth が通ったら、手元の Codex client を切り替えます。

CLIProxyAPI の Codex client 設定では、主に次の二つを触ります。

  • ~/.codex/config.toml
  • ~/.codex/auth.json

remote proxy を使うなら、config.toml では自分の endpoint を provider として指定します。

model_provider = "cliproxyapi"
model = "gpt-5-codex"
model_reasoning_effort = "high"

[model_providers.cliproxyapi]
name = "cliproxyapi"
base_url = "https://codex-proxy.example.com/v1"
wire_api = "responses"

特に間違いやすいのは二点です。

base_url

remote server に置いたのに、公式例の http://127.0.0.1:8317/v1 をそのまま残してはいけません。

それでは local PC 上の 8317 を探します。

wire_api

wire_api = "responses" を忘れないことです。

CLIProxyAPI の Codex 接続は Responses API の流れで使います。

auth.json の OPENAI_API_KEY は upstream key とは限らない

公式例では次のような形があります。

{
  "OPENAI_API_KEY": "sk-dummy"
}

初めて見ると「proxy を使うのになぜ OpenAI key が必要なのか」と感じます。

ここでは、Codex client 側の設定構造を満たす placeholder として理解した方が分かりやすいです。

本当に upstream へアクセスする認証状態は CLIProxyAPI 側の OAuth / token にあります。

そのため、自分の本物の upstream secret を不用意にローカル client へ戻す必要はありません。

構造は二段です。

上流:
CLIProxyAPI が保持する OAuth / token
        ↓
下流:
Codex や各 project が proxy 用 api-key でアクセス

この分離が proxy layer の大きな価値です。

Nginx で正式な endpoint にする

8317 を直接外へ出すより、自分の domain と HTTPS の後ろに置く方が管理しやすいです。

例えば codex-proxy.example.com なら、重要なのは /v1/ path を維持することです。

server {
  listen 443 ssl http2;
  server_name codex-proxy.example.com;

  location /v1/ {
    proxy_pass http://127.0.0.1:8317/v1/;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

path を見た目の都合で変えてしまうと、OpenAI-compatible client 側と合わなくなります。

安定した /v1 endpoint ができれば、Codex 専用 proxy ではなく他の self-hosted tool にも使えます。

例えば OpenAI-compatible endpoint を設定できる project なら、

OPENAI_BASE_URL=https://codex-proxy.example.com/v1
OPENAI_API_KEY=<proxy-api-key-for-this-project>

のように接続できます。

本当に便利なのはここです。

上流の OAuth、account、model routing を proxy layer に集中させ、下流は「endpoint + project 用 key」だけを見る構成になります。

複数 project で共通化する意味

最初は Codex だけでも、後から次のような client が増えることがあります。

  • 別の AI coding tool
  • self-hosted chat frontend
  • Agent panel
  • automation script
  • internal tool

それぞれに upstream token を保存すると、どの container に何を入れたか分からなくなりやすいです。

proxy を入れると、upstream state は一か所です。

下流側では、

  • どの key を使うか
  • どの domain / endpoint へ向けるか
  • project 単位で rate limit / log を分けるか

を管理すればよくなります。

最初は内部 project で一つの proxy key を共有しても構いません。

project が増えたら key を分割し、個別 revoke、rate limit、log separation を追加できます。

実際によく起きる失敗

私が特に注意するのは次です。

  • service は起動したが auth/ に OAuth state がない
  • local config.toml の base_url が localhost のまま
  • Nginx で /v1/ path を落としている
  • wire_api = "responses" を忘れている
  • auth.json に本物の upstream key を入れる必要があると誤解する

どれも Docker の難しい問題というより、各 layer の役割を混同した結果です。

公式ログインでは認証と client が一体に見えます。

CLIProxyAPI では、

  • upstream login
  • proxy service
  • reverse proxy
  • local client

が分かれます。

自由度が上がる代わりに、最初の一回はこの topology を頭の中に持つ必要があります。

直接ログインと proxy はどちらが良いか

私の判断は単純です。

一台の PC ですぐ使うだけなら公式 direct login。

Codex を自分の AI infrastructure の一部として管理するなら proxy。

前者は低摩擦です。

後者は、

  • 複数 machine
  • 複数 client
  • upstream state の集中
  • access key の分離
  • routing
  • log
  • account 切り替え

などが必要になるほど価値が上がります。

そして一度 infrastructure として扱うなら、config.yaml と auth/ も state です。

container image は再取得できますが、認証状態や細かな設定を失うと復旧に時間がかかります。

長期運用するならこの二つも backup 対象にします。

Codex 自体の workflow 変化を知りたいなら 新しい Codex は何が変わったのか、server 側の state backup なら Docker Volume の自動バックアップ が関連します。

関連資料