适用场景
手里同时用着 OpenAI、Claude、通义千问、DeepSeek、本地 Ollama 等多个大模型服务,每个厂商一套密钥、一份账单、一种调用格式,代码里到处是分支判断。这套方案用 one-api 把这些上游统一收敛成一个 OpenAI 兼容的地址,客户端只改 base_url 和 key,就能切换任意模型。
它也适合团队内部做 API 网关:按人发令牌、按令牌限额度、按模型设倍率,谁的用量多少在后台一目了然。
环境与前置条件
操作系统:主流 Linux 发行版(Ubuntu、Debian、CentOS、Rocky 等)均可,macOS 可作本地验证,Windows 建议用 WSL2 或 Docker Desktop。
运行时:Docker 与 Docker Compose。具体最低版本要求以官方文档当前版本为准。
硬件建议:
| 场景 | CPU/内存 | 磁盘 |
|---|---|---|
| 个人试用 | 1 核 1G | 5 GB |
| 小团队(10 人内) | 2 核 2G | 10 GB |
| 正式对外服务 | 4 核 4G 起 | 20 GB 起(建议 MySQL) |
one-api 本身是纯转发层,不跑模型推理,所以不需要 GPU,也不吃显存。资源的瓶颈通常在数据库连接数和并发网络 IO。
网络:服务器需要能出网访问各上游 API 域名。如果接的是海外厂商,确认服务器的出口线路能连通;连不通时需要在渠道里配置代理地址,见「常见报错」第 5 条。
数据库:默认使用内置 SQLite,单文件存在数据目录里,够用且省事。多实例部署或数据量较大时改接 MySQL / PostgreSQL,通过环境变量指定连接串。
分步骤部署
步骤 1:安装 Docker
已有 Docker 的可以跳过。用官方脚本安装:
```bash
curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker
docker version
```
看到 Client 和 Server 两段版本信息,说明 Docker 就绪。
步骤 2:准备数据目录
one-api 把 SQLite 数据库和日志放在容器内 /data 目录,必须挂载出来,否则容器重建数据就没了。
```bash
sudo mkdir -p /opt/one-api/data
sudo chmod -R 777 /opt/one-api/data
```
生产环境可以把权限收紧到容器运行用户可读写即可,这里为了先跑通用宽松权限。
步骤 3:启动容器
```bash
docker run --name one-api \
-d \
--restart always \
-p 3000:3000 \
-e TZ=Asia/Shanghai \
-v /opt/one-api/data:/data \
songquanpeng/one-api:latest
```
说明几点:
- 镜像名称与标签以官方文档当前发布的为准,示例使用
latest。正式环境建议固定到具体版本标签,避免某次拉取新镜像后行为变化。 -p 3000:3000表示宿主机 3000 端口映射到容器 3000 端口。3000 被占用就换成-p 3001:3000。- 想改端口、加多实例会话密钥时,追加环境变量
-e SESSION_SECRET=一串随机字符串,多实例部署时各实例必须一致,否则会出现登录后反复跳回登录页。 - 需要外部数据库时追加
-e SQL_DSN='用户名:密码@tcp(数据库地址:3306)/数据库名';需要 Redis 做缓存时追加-e REDIS_CONN_STRING='redis://127.0.0.1:6379'。连接串格式以官方文档为准。
执行 docker ps,看到 one-api 容器状态为 Up 即为成功。查看启动日志:
```bash
docker logs -f one-api
```
日志里出现监听端口的提示、且没有反复报错刷屏,就可以进入下一步。
步骤 4:登录后台并修改默认密码
浏览器打开 http://服务器IP:3000。首次登录使用镜像约定的初始管理员账号密码,具体初始值以官方文档和镜像说明为准(常见为 root / 123456)。登录后第一件事就是改密码:右上角进入个人信息页修改,否则等于把网关裸奔在公网上。
如果你只想先在内网用,也建议顺手在安全组里把 3000 端口限制到办公网 IP。
步骤 5:添加第一个渠道
渠道 = 一个上游 API 提供方。进入「渠道」→「添加新的渠道」,关键字段:
| 字段 | 说明 |
|---|---|
| 类型 | OpenAI、Azure、Claude、Gemini 等有独立类型;其他兼容 OpenAI 协议的厂商选「自定义渠道」或 OpenAI 类型 |
| 名称 | 自己看得懂即可,如 deepseek-主力 |
| 分组 | 默认 default,可另建 vip 等分组 |
| 模型 | 该渠道支持的模型名,逗号分隔,如 gpt-4o-mini, gpt-4o |
| 密钥 | 上游厂商的 API Key |
| 代理地址 | 上游的 Base URL。官方 OpenAI 可留空,第三方兼容服务必须填,通常形如 https://xxx.com,不带 /v1 |
| 模型重定向 | 选填。把用户请求的模型名映射到上游真实模型名,例如把 gpt-4o 映射成上游的 gpt-4o-2024-xx,实现「对外名字统一、对内各走各家」 |
模型名要逐个写清楚,写错一个字符,调用时就会报「无可用渠道」。多个同类上游(比如两个不同的 OpenAI 账号)可以建多个渠道,one-api 会按优先级和权重做负载均衡。
步骤 6:测试渠道
渠道列表里每一行右侧有「测试」按钮,点击后用该渠道配置向真实上游发一次最小请求。返回绿色对勾表示连通;返回红色感叹号时把鼠标悬停在提示上看具体错误。
建议逐个模型测:有些渠道 key 有效但没开通某个模型的权限,整渠道测试通过、单独调用某个模型仍会失败。
步骤 7:创建令牌(对外使用的 Key)
进入「令牌」→「添加新的令牌」:
- 名称:给谁用就写谁,方便对账。
- 额度:该令牌最多能消耗多少额度,填 0 或不填表示不限制。
- 过期时间:按需设置,长期不用的令牌建议设短期。
- 分组:必须与渠道分组有交集,否则调用会提示无可用渠道。
- 模型限制:可以只放开部分模型,防止有人拿你的 key 去跑高价模型。
保存后会生成一串 sk- 开头的 key,页面只完整显示一次,复制保存好。
步骤 8:配置计费倍率与分组
这是 one-api 区别于普通反向代理的地方。计费由三个倍率相乘决定:
模型倍率:决定该模型每单位 token 扣多少额度。基准是「1 倍率对应的额度单价」,具体换算规则以官方系统设置页的说明和官方文档为准。实操上按上游官方定价成比例填写即可——比如某模型输入价是基准模型的 5 倍,就把倍率填成基准倍率的 5 倍;同系列的新模型上线后,先查上游价格表再填,不要凭感觉给数。
补全倍率:输出 token 的加权系数。因为多数模型输出单价高于输入,这个值通常大于 1。设成 2 就表示输出 token 按 2 倍计入消耗。
分组倍率:对整个分组统一打折或加价。例如 default 设为 1,vip 设为 0.8,则 vip 分组下所有调用消耗按八折计。
配置入口在「系统设置 / 运营设置」里的「模型倍率」「补全倍率」「分组倍率」。改完立即生效,不需要重启容器。
一个常见坑:倍率配完发现余额掉得飞快,通常是「模型倍率填成了上游的美元单价而不是相对倍率」——比如把 0.002 当成倍率填进去,虽然数值小,但和基准倍率的量纲不一致,算出来的额度会错得离谱。先确认基准规则再填数。
步骤 9(可选):加一层反向代理
直接用 IP+端口访问不方便,也不安全。用 Nginx 或 Caddy 在前面套一层域名和 HTTPS:
```nginx
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
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_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_buffering off;
}
}
```
proxy_buffering off 对流式输出(stream)很关键,开着缓冲会让前端等很久才看到第一个字。proxy_read_timeout 建议放大,长回答容易超过默认的 60 秒。
验证部署是否成功
第一层:容器存活
```bash
docker ps --filter name=one-api
curl -i http://127.0.0.1:3000/api/status
```
预期:容器状态 Up;curl 返回 HTTP/1.1 200,响应体是一段 JSON,包含系统状态字段。
第二层:端到端调用
用上一步生成的令牌,发一次真实请求(模型名换成你渠道里配置过的):
```bash
curl http://127.0.0.1:3000/v1/chat/completions \
-H "Authorization: Bearer sk-你的令牌" \
-H "Content-Type: application/json" \
-d '{
"model": "你的模型名",
"messages": [{"role": "user", "content": "用一句话介绍你自己"}],
"stream": false
}'
```
预期:返回标准 OpenAI 格式的 JSON,choices[0].message.content 里有模型回答。同时后台「日志」页面会新增一条记录,能看到消耗的 token 数和扣减的额度——这条记录出现,说明计费链路也通了。
第三层:多上游切换
把 model 换成另一个渠道下的模型名再请求一次,同样成功,说明多上游聚合生效。
常见报错与解决
1. Error response from daemon: driver failed programming external connectivity ... bind: address already in use
→ 原因:宿主机 3000 端口被别的进程占用。
→ 解决:
```bash
sudo ss -lntp | grep :3000
方案 A:停掉占用进程
方案 B:改用其他端口重新创建容器
docker rm -f one-api
docker run --name one-api -d --restart always -p 3001:3000 \
-e TZ=Asia/Shanghai -v /opt/one-api/data:/data \
songquanpeng/one-api:latest
```
2. 容器反复重启,日志出现 unable to open database file
→ 原因:挂载的 /opt/one-api/data 目录容器内不可写,SQLite 建不了库文件。
→ 解决:
```bash
sudo chown -R 1000:1000 /opt/one-api/data 2>/dev/null || sudo chmod -R 777 /opt/one-api/data
docker restart one-api
docker logs --tail 50 one-api
```
3. 调用返回 当前分组 default 下对于模型 xxx 无可用渠道
→ 原因:三处不匹配之一——渠道的「模型」列表里没有这个模型名;令牌的分组和渠道分组对不上;渠道被禁用或已自动禁用。
→ 解决:进入「渠道」,确认该渠道状态为「已启用」、模型列表里确实有这个名字(注意大小写和连字符);再进入「令牌」,确认分组与渠道分组一致。修好后点一次「测试」验证。
4. 调用返回 401 invalid api key 或 Incorrect API key provided
→ 原因:上游密钥错误、已过期,或者代理地址填错(多写了 /v1、用了 http 而不是 https、漏了域名后缀)。
→ 解决:先用 curl 直接打上游验证 key 本身可用,排除密钥问题后再检查渠道里的「代理地址」。one-api 的代理地址一般填到域名根,不带 /v1。
```bash
curl https://上游域名/v1/models -H "Authorization: Bearer 上游key"
```
5. 渠道测试报 context deadline exceeded / connection timed out
→ 原因:服务器访问不到上游(常见于海外厂商),或被防火墙拦截。
→ 解决:先测连通性:
```bash
curl -I --max-time 10 https://上游域名
```
不通的话,要么给服务器换出口线路,要么在渠道配置里填写可用的代理地址。也可以给容器设置全局代理环境变量后重建容器:
```bash
docker run --name one-api -d --restart always -p 3000:3000 \
-e TZ=Asia/Shanghai \
-e HTTPS_PROXY=http://代理地址:端口 \
-v /opt/one-api/data:/data \
songquanpeng/one-api:latest
```
6. 日志报 dial tcp ...: connect: connection refused(Redis 相关)
→ 原因:配置了 REDIS_CONN_STRING 但 Redis 没起、地址写错,或容器里写的是 127.0.0.1(容器内的 127.0.0.1 不是宿主机)。
→ 解决:确认 Redis 在跑,并把连接串里的地址改成可达的 IP 或服务名:
```bash
docker exec -it one-api sh -c 'ping -c 2 redis'
```
如果暂时不需要 Redis,直接去掉这个环境变量重建容器即可,单实例不必强上 Redis。
7. 登录成功后页面反复跳回登录页
→ 原因:多实例部署时 SESSION_SECRET 各实例不一致,或反向代理没透传 X-Forwarded-Proto,导致 Cookie 判定为不安全。
→ 解决:给所有实例设置同一个 SESSION_SECRET,并在 Nginx 配置里确认有 proxy_set_header X-Forwarded-Proto $scheme;。
后续维护
备份
SQLite 模式下,数据全在 /opt/one-api/data,直接打包这个目录即可:
```bash
docker stop one-api
sudo tar czf /backup/one-api-$(date +%F).tar.gz -C /opt one-api/data
docker start one-api
```
用 MySQL 的话改用 mysqldump 导出对应库。建议做成定时任务,保留最近若干份。注意备份里包含所有上游密钥,存放位置要限权。
升级
```bash
docker pull songquanpeng/one-api:latest
docker rm -f one-api
用与首次部署完全相同的 docker run 命令重新创建容器
```
数据在挂载目录里,容器重建不会丢。升级前先备份,升级后先点几个渠道测试再放开流量。不要在生产环境直接追 latest,稳妥做法是固定版本标签、先在测试机验证。
日志与监控
- 应用日志:
docker logs --tail 200 one-api,排查上游错误主要看这里。可以配置 Docker 的日志轮转,避免单文件无限增长(--log-opt max-size=50m --log-opt max-file=3)。 - 业务日志:后台「日志」页面可以按用户、令牌、模型筛选,是排查「谁在什么时候消耗了多少额度」的主要入口。
- 健康检查:定期请求
/api/status,非 200 或超时就告警。 - 关键指标建议盯三个:上游渠道的失败率(渠道被自动禁用说明某个 key 出问题了)、单令牌的消耗增速(异常飙升可能是密钥泄露)、容器内存占用(长期运行若持续上涨,重启容器观察是否为内存泄漏)。
额度与权限治理
定期清理长期不用的令牌;给对外暴露的令牌都设上限和过期时间;高价模型单独建分组并限制可用令牌范围。上游厂商调价后,记得同步更新模型倍率,否则账面额度和真实成本会慢慢脱节。
