# CLIProxyAPI + Codex：Docker、OAuth、Reverse Proxy の構成方法

> Canonical: https://vxi.me/ja/posts/cliproxyapi-codex-docker-proxy/
> Locale: ja-jp
> Published: 2026-03-30
> Updated: 2026-10-14
> Markdown: https://vxi.me/ja/posts/cliproxyapi-codex-docker-proxy.md

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

<a class="gh-repo-pill" href="https://github.com/kuangyongjie/cliproxyapi-codex-deploy" target="_blank" rel="noopener"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg><span>kuangyongjie/cliproxyapi-codex-deploy</span></a>

```bash
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](https://github.com/router-for-me/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 に向けること」は別の作業です。

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

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

```text
/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` の中で、初期段階に見るのは例えばこの辺です。

```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 する

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

```yaml
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 を使います。

```bash
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 を開きます。
   ```bash
   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.host` | `host` | bind する interface。空文字は全 interface に bind します。 |
| `server.port` | `port` | client が呼ぶ API port。本ガイドでは `8317`。 |
| `oauth.auth-dir` | `auth-dir` | Codex OAuth state の保存先。`auth/` の mount と一致させないと restart で login が消えます。 |
| `access.api-keys` | `api-keys` | 下流 client に渡す key。upstream の OpenAI credential では*ありません*。 |
| `management.allow-remote` | `remote-management.allow-remote` | management API を公開する明確な理由がなければ `false` のままにします。 |
| `management.secret-key` | `remote-management.secret-key` | management API の key。空にすると management API 自体が無効になります。 |
| `client.codex.optimize-multi-agent-v2` | — | 任意。Codex Desktop / codex-tui の multi-agent 構成向け最適化。デフォルト `false`。 |

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

```yaml
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 を保ちます。

```text
/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 が失われます。

起動して様子を見ます。

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

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

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

```bash
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 として指定します。

```toml
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 とは限らない

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

```json
{
  "OPENAI_API_KEY": "sk-dummy"
}
```

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

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

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

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

構造は二段です。

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

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

## Nginx で正式な endpoint にする

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

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

```nginx
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 なら、

```bash
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 は何が変わったのか](/ja/posts/what-changed-in-the-new-codex/)、server 側の state backup なら [Docker Volume の自動バックアップ](/ja/posts/docker-volume-backup-github-sync/) が関連します。

## 関連資料

- [CLIProxyAPI GitHub](https://github.com/router-for-me/CLIProxyAPI)
- [CLIProxyAPI Docker](https://help.router-for.me/docker/docker.html)
- [CLIProxyAPI Docker Compose](https://help.router-for.me/docker/docker-compose.html)
- [CLIProxyAPI Codex client](https://help.router-for.me/agent-client/codex.html)
