春江暮客

春江暮客的个人学习分享网站

Codex 接入 LiteLLM 实战:用 Nginx 做统一模型入口

2026-06-02 技术
Codex 接入 LiteLLM 实战:用 Nginx 做统一模型入口

Codex 可以接入自定义模型入口,但如果你同时使用 OpenAI、Qwen、DeepSeek、Claude 等 provider,配置很容易分散:每个工具都要维护一套 key、base URL 和模型名。

这篇文章记录一套更好维护的做法:先用 LiteLLM 在服务器上统一模型别名,再用 Nginxhttps://www.bobobk.com/v1 反向代理到本地 LiteLLM,最后让 Codex 只连接这个统一入口。

完成后,请求链路会变成这样:

Codex
  -> https://www.bobobk.com/v1
  -> Nginx location /v1
  -> http://127.0.0.1:4000
  -> LiteLLM model aliases
  -> OpenAI / DashScope / DeepSeek / Anthropic

前提是你已经安装 Codex,并且服务器域名已经配置好 HTTPS。如果还没有安装 Codex,可以先使用官方安装脚本:

curl -fsSL https://chatgpt.com/codex/install.sh | sh

如果安装失败,通常是网络访问问题。先配置代理,或者在可以访问外网的服务器上安装。

方法 1:先确定目录和目标

本文使用的 LiteLLM 配置放在站点目录下面:

/home/wwwroot/bobobk.com/llm
├── config.yaml
├── docker-compose.yml
├── .env.example
├── run.sh
├── check.sh
└── litellm-proxy.service.example

目标很明确:

  1. LiteLLM 只监听服务器本地 4000 端口
  2. Nginx 对外暴露 HTTPS 地址 /v1
  3. Codex 使用自定义 provider bobobk
  4. 模型 key 只放在 llm/.env 和本机环境变量里
  5. 博客、配置示例和 Git 仓库里不出现真实 API key

方法 2:配置 LiteLLM 模型别名

1. 准备 .env

进入 llm 目录,复制环境变量模板:

cd /home/wwwroot/bobobk.com/llm
cp .env.example .env
nano .env

.env 里至少需要一个 LiteLLM master key。这个 key 是客户端访问 LiteLLM 时使用的 Bearer token:

LITELLM_MASTER_KEY=sk-change-me-long-random-value
LITELLM_HOST=0.0.0.0
LITELLM_PORT=4000
LITELLM_LOG=INFO

OPENAI_API_KEY=
DASHSCOPE_API_KEY=
DEEPSEEK_API_KEY=
ANTHROPIC_API_KEY=

实际使用时,把 LITELLM_MASTER_KEY 换成足够长的随机值,并填入你准备启用的 provider key。

2. 编写 config.yaml

config.yaml 的核心是 model_list。这里把不同 provider 包装成几个稳定的模型别名:

model_list:
  - model_name: gpt-5.5
    litellm_params:
      model: openai/gpt-5.5
      api_key: os.environ/OPENAI_API_KEY
      timeout: 120
      rpm: 60

  - model_name: qwen3.7-max
    litellm_params:
      model: openai/qwen3.7-max
      api_base: https://dashscope-intl.aliyuncs.com/compatible-mode/v1
      api_key: os.environ/DASHSCOPE_API_KEY
      timeout: 120
      rpm: 60

  - model_name: deepseek-chat
    litellm_params:
      model: deepseek/deepseek-chat
      api_key: os.environ/DEEPSEEK_API_KEY
      timeout: 120
      rpm: 60

  - model_name: claude-4.6
    litellm_params:
      model: anthropic/claude-4-6-sonnet-latest
      api_key: os.environ/ANTHROPIC_API_KEY
      timeout: 120
      rpm: 60

router_settings:
  routing_strategy: simple-shuffle
  num_retries: 2
  max_fallbacks: 2

litellm_settings:
  drop_params: true
  request_timeout: 120

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

fallbacks:
  - gpt-5.5:
      - qwen-3.7max
      - deepseek-chat
  - qwen-3.7max:
      - deepseek-chat
  - claude-4.6:
      - deepseek-chat

这里有几个实用点:

  1. model_name 是 Codex 看到的模型名
  2. api_key: os.environ/xxx 避免把 key 写进 YAML
  3. drop_params: true 让不同客户端传来的多余参数不容易打断请求
  4. fallbacks 可以在主模型失败时切到备用模型

方法 3:启动 LiteLLM

1. 本地命令启动

run.sh 会自动读取当前目录的 .env,然后启动 LiteLLM:

cd /home/wwwroot/bobobk.com/llm
chmod +x run.sh check.sh
./run.sh

脚本里的关键命令是:

exec litellm --config "$CONFIG_FILE" --host "$HOST" --port "$PORT"

如果你希望先在当前 shell 里测试,可以直接执行:

export LITELLM_MASTER_KEY=sk-change-me-long-random-value
litellm --config config.yaml --host 0.0.0.0 --port 4000

2. Docker Compose 启动

如果更喜欢容器化运行,可以用仓库里的 docker-compose.yml

cd /home/wwwroot/bobobk.com/llm
docker compose up -d
docker compose logs -f litellm

这个 compose 文件会读取 .env,把 config.yaml 只读挂载到容器里,并把容器端口 4000 暴露到服务器本地。

3. systemd 启动

长期运行时可以使用 systemd 模板:

cd /home/wwwroot/bobobk.com/llm
sudo cp litellm-proxy.service.example /etc/systemd/system/litellm-proxy.service
sudo systemctl daemon-reload
sudo systemctl enable --now litellm-proxy
sudo systemctl status litellm-proxy

复制前先检查 UserGroupWorkingDirectoryExecStart 是否符合你的服务器路径。

方法 4:用 Nginx 暴露 /v1

LiteLLM 本身跑在 127.0.0.1:4000,不要直接把它裸露到公网。bobobk.com 的做法是在 HTTPS 站点里增加一个 /v1 反向代理:

server {
    listen 443 ssl;
    http2 on;
    server_name bobobk.com www.bobobk.com;
    root /home/wwwroot/bobobk.com/public/;

    location /v1 {
        proxy_pass http://127.0.0.1:4000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

修改后检查并重载 Nginx:

sudo nginx -t
sudo systemctl reload nginx

这样外部访问:

https://www.bobobk.com/v1

实际会进入:

http://127.0.0.1:4000

认证仍然由 LiteLLM 的 LITELLM_MASTER_KEY 控制。

方法 5:配置 Codex 自定义 provider

Codex 的配置文件在:

/home/teng/.codex/config.toml

关键配置如下:

model = "gpt-5.5"
model_provider = "bobobk"

[projects."/home/wwwroot/bobobk.com"]
trust_level = "trusted"

[model_providers.bobobk]
name = "bobobk"
base_url = "https://www.bobobk.com/v1"
env_key = "LITELLM_MASTER_KEY"
wire_api = "responses"

这段配置的含义:

  1. model = "gpt-5.5" 让 Codex 默认请求 LiteLLM 里的 gpt-5.5 别名
  2. model_provider = "bobobk" 指向下面自定义 provider
  3. base_url 使用 Nginx 暴露的 HTTPS /v1
  4. env_key 告诉 Codex 从环境变量读取 Bearer token
  5. wire_api = "responses" 让 Codex 按 Responses API 的协议发送请求

启动 Codex 前,在 shell 里导出同一个 master key:

export LITELLM_MASTER_KEY=sk-change-me-long-random-value
codex

如果你使用 zsh,可以写入 ~/.zshrc

export LITELLM_MASTER_KEY=sk-change-me-long-random-value

然后重新加载:

source ~/.zshrc

方法 6:验证链路

1. 检查 LiteLLM 本地端口

在服务器上执行:

cd /home/wwwroot/bobobk.com/llm
./check.sh

正常情况下会看到 readiness 输出:

Readiness:
{"status":"healthy"}

如果设置了 LITELLM_MASTER_KEY,脚本还会请求模型列表:

curl -fsS http://127.0.0.1:4000/v1/models \
  -H "Authorization: Bearer ${LITELLM_MASTER_KEY}"

2. 检查 Nginx HTTPS 入口

从服务器或本机执行:

curl -fsS https://www.bobobk.com/v1/models \
  -H "Authorization: Bearer ${LITELLM_MASTER_KEY}"

能返回模型列表,就说明 Nginx 到 LiteLLM 的代理是通的。

3. 发送一次 Responses 请求

因为 Codex 配置里使用了 wire_api = "responses",可以先用 Responses 格式做一次 smoke test:

curl https://www.bobobk.com/v1/responses \
  -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "input": "Reply with one short sentence.",
    "max_output_tokens": 32
  }'

如果你的 LiteLLM 版本或上游模型更适合 Chat Completions,也可以额外测试:

curl https://www.bobobk.com/v1/chat/completions \
  -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "messages": [
      {"role": "user", "content": "Reply with one short sentence."}
    ],
    "max_tokens": 32
  }'

只要模型请求能返回内容,Codex 侧通常只需要确认 modelmodel_providerenv_keywire_api 是否匹配。

4. 查看 Codex 实际状态

配置好后,进入目标目录并启动 Codex:

cd /home/wwwroot/bobobk.com
codex

启动界面会显示当前模型和目录,例如:

⚠ Codex could not find bubblewrap on PATH. Install bubblewrap with your OS package manager.

╭───────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.136.0)                │
│                                           │
│ model:     gpt-5.5   /model to change │
│ directory: /home/wwwroot/bobobk.com       │
╰───────────────────────────────────────────╯

输入 /status 后,可以看到 provider 是否已经切到自己的 API 入口:

/status

╭─────────────────────────────────────────────────────────────────────╮
│  >_ OpenAI Codex (v0.136.0)                                         │
│                                                                     │
│  Model:                gpt-5.5 (reasoning none, summaries auto)     │
│  Model provider:       bobobk - https://www.bobobk.com/v1           │
│  Directory:            /home/wwwroot/bobobk.com                     │
│  Permissions:          Workspace (Ask for approval)                 │
│  Agents.md:            AGENTS.md                                    │
│  Collaboration mode:   Default                                      │
│  Token usage:          0 total  (0 input + 0 output)                │
╰─────────────────────────────────────────────────────────────────────╯

看到 Model provider: bobobk - https://www.bobobk.com/v1,就说明 Codex 已经启用自己的 API 入口。

常见问题

1. Codex 提示认证失败

原因通常是 Codex 当前 shell 没有 LITELLM_MASTER_KEY

检查:

echo "$LITELLM_MASTER_KEY"

修复:

export LITELLM_MASTER_KEY=sk-change-me-long-random-value
codex

2. /v1/models 返回 401

原因是没有带 Authorization header,或者 header 里的 key 和 LiteLLM .env 不一致。

修复:

curl -fsS https://www.bobobk.com/v1/models \
  -H "Authorization: Bearer ${LITELLM_MASTER_KEY}"

3. Nginx 返回 502

原因通常是 LiteLLM 没启动,或者端口不是 4000

检查:

ss -lntp | grep 4000
cd /home/wwwroot/bobobk.com/llm
./check.sh

修复:

cd /home/wwwroot/bobobk.com/llm
./run.sh

4. Responses 请求失败,但 chat completions 可用

原因通常是 LiteLLM 版本、上游 provider 或模型别名没有正确支持 Responses 格式。

先用 chat completions 确认模型本身可用:

curl https://www.bobobk.com/v1/chat/completions \
  -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "messages": [
      {"role": "user", "content": "Reply with ok."}
    ],
    "max_tokens": 16
  }'

如果 chat completions 正常,但 Codex 仍然失败,就需要升级 LiteLLM,或者把 Codex provider 的 wire_api 调整为当前 Codex 支持的 OpenAI-compatible chat 配置。

5. 某个模型别名不可用

原因通常是 provider key 没填,或者 model 名称写错。

检查对应环境变量:

grep -E 'OPENAI_API_KEY|DASHSCOPE_API_KEY|DEEPSEEK_API_KEY|ANTHROPIC_API_KEY' .env

修复后重启 LiteLLM:

sudo systemctl restart litellm-proxy

如果你是用 Docker Compose:

docker compose restart litellm

总结

这套配置的核心是把模型访问收敛到一个稳定入口:LiteLLM 管模型别名、fallback 和 provider key,Nginx 管 HTTPS 和公网入口,Codex 只关心一个 base_url 和一个默认模型名。

真实 API key 不应该写进 Codex 配置、Hugo 文章或 Git 仓库。把密钥放进 .env 和 shell 环境变量,再通过 env_key 传给 Codex,后续切换模型或 provider 时只需要改 LiteLLM 配置。

友情链接

其它