如果你已经有 Claude、OpenAI 或 Gemini 账号,想在 Codex、Cherry Studio 等客户端里使用,可以在自己的 Ubuntu 服务器上部署 Sub2API。账号保存在网关后台,客户端只填写网关地址和单独生成的 API Key,不需要拿到原账号的登录信息。
页面底部的下载区提供了一套面向空白 Ubuntu 24.04 服务器的 Sub2API 主机部署脚本包。它从管理电脑通过 SSH 把脚本传到服务器,再依次配置 Ubuntu、Docker、Sub2API、PostgreSQL、Redis 和 Caddy。
选择部署方式并准备 Ubuntu 服务器
先根据服务器当前的环境选择部署方式:
| 服务器现状 | 使用方式 |
|---|---|
| 空白的 Ubuntu 24.04 独立服务器 | 运行完整脚本,由脚本安装 Docker、部署 Sub2API 并配置 Caddy |
| 已经安装 Docker,80/443 尚未被其他服务使用 | 添加 --skip-system,跳过 Ubuntu 配置和 Docker 安装 |
| 已经运行 Nginx、Caddy 或其他网站 | 使用官方 Docker Compose 部署,再把 Sub2API 接入现有反向代理;不要让完整脚本接管 80/443 |
使用官方 Docker Compose 时,跳过后面的主机脚本命令;域名能够通过 HTTPS 打开后,从“登录后台并修改管理员账号”继续。
完整脚本的执行顺序
完整脚本从管理电脑发起。它先检查参数和 SSH 连接,再把 provisioning、host-gateway 与 sub2api 三个目录同步到服务器;后续的系统配置、Compose 文件、Caddy 入口和部署检查都在服务器上执行。
“系统加固”会修改哪些设置
这里的“系统加固”指脚本会实际修改的 Ubuntu 设置:启用 UTC 与 NTP,安装基础运维包,关闭 SSH 的 root 登录和密码登录,只允许指定运维用户使用密钥登录,并配置 fail2ban、自动安全更新、UFW 和 8 GB swap。UFW 放行 SSH、80 和 443;Docker 的配置还会启用日志轮转,并把 journald 的最大占用设为 500 MB。
添加 --skip-system 后,脚本不会执行这些 Ubuntu 设置,也不会安装或重新配置 Docker。它仍会确认运维用户、生成或复用环境密钥、写入 Compose、建立持久化目录、配置 Caddy、启动三个容器并运行部署检查。因此,这个参数只适合已经按自己的方式完成系统配置和 Docker 安装、并且 80/443 没有被其他服务占用的服务器。
完整脚本只适配 Ubuntu 24.04,因为其中包含 Ubuntu 的软件源、SSH、UFW 和 Docker 安装配置。服务器还需要 sudo 权限、可用的公网 IPv4、一个已经解析到该地址的域名,以及能够通过 SSH 登录的端口。
个人或小团队可以先准备 2 核 4 GB 的服务器。磁盘空间要同时容纳 Sub2API、PostgreSQL、Redis、容器日志、Docker 镜像和一份备份:
所需空间 ≈ Sub2API 数据 + PostgreSQL 数据 + Redis 数据
+ 容器日志与 Docker 镜像 + 一份备份
+ 30% 余量
域名示例使用 sub2api.example.com。添加 A 记录后,确认解析结果与服务器公网地址一致:
dig +short sub2api.example.com A
curl -4 https://ifconfig.me
云安全组和主机防火墙都要允许 80/443;8080 不应加入公网规则。
| 端口 | 允许来源 | 用途 |
|---|---|---|
| 22/tcp | 管理网络或固定来源 | SSH 管理 |
| 80/tcp | 公网 | ACME HTTP 验证与 HTTPS 跳转 |
| 443/tcp | 公网 | 管理后台与 API 请求 |
| 8080/tcp | 仅 127.0.0.1 | Caddy 到 Sub2API 的回环连接 |
| 5432、6379 | 不发布到宿主机 | PostgreSQL 与 Redis 的容器内连接 |
下载脚本并部署 Sub2API
选择完整脚本或 --skip-system 时,下载下面的脚本包。服务器已经有 Nginx、Caddy 或其他网站时,改用官方的 Docker Compose 部署(在新标签页打开),并沿用现有 HTTPS 入口,不执行这个主机脚本包。
- 下载:Sub2API 主机部署脚本包(62 KB)
- SHA-256:
d159ab62a05aeacc5f3238fb84a00c24ee5ef8bf6302bd93d333f5bdaeb74e21
先核对下载结果:
shasum -a 256 sub2api-deploy.tar.gz
# Linux 使用:sha256sum sub2api-deploy.tar.gz
tar -tzf sub2api-deploy.tar.gz | less
解包后保持 provisioning/、host-gateway/ 与 sub2api/ 三个目录的相对位置不变:
tar -xzf sub2api-deploy.tar.gz
cd sub2api-deploy
export SERVER_IP="203.0.113.10"
export SSH_KEY_PATH="$HOME/.ssh/id_ed25519"
bash deployments/scripts/sub2api/provision-sub2api-host.sh \
--host "${SERVER_IP}" \
--domain sub2api.example.com \
--ssh-user ubuntu \
--ssh-key "${SSH_KEY_PATH}" \
--dry-run
--dry-run 只显示参数、连接目标和即将执行的阶段,不同步文件,也不修改远端。输出中的主机、域名、SSH 用户和镜像都正确后,去掉 --dry-run 正式执行:
bash deployments/scripts/sub2api/provision-sub2api-host.sh \
--host "${SERVER_IP}" \
--domain sub2api.example.com \
--ssh-user ubuntu \
--ssh-key "${SSH_KEY_PATH}"
脚本固定使用 weishaw/sub2api:0.2.4。这是脚本包的验证版本,不代表当前最新版本;Sub2API Releases(在新标签页打开) 出现新版本时,也不会在重复部署中自动替换正在运行的镜像。
这些参数会改变部署行为:
| 参数 | 作用 |
|---|---|
--sub2api-image | 显式指定要部署的镜像版本 |
--deploy-user | 指定负责 sudo 与 Docker 运维的用户 |
--skip-system | 主机已按自己的方式完成 Ubuntu 配置并安装 Docker 时,跳过这两个阶段 |
--skip-start | 只写入配置,不启动容器和入口 |
--skip-dns-check | 暂时不检查域名解析;不会替你创建 DNS 记录 |
脚本不调用云厂商 API。购买实例、开放安全组和添加 DNS 记录仍要在对应控制台完成。
检查 HTTPS 和服务状态
脚本把运行文件与数据分开保存。环境文件已经存在时,不会重新生成 PostgreSQL 密码、JWT_SECRET 或 TOTP_ENCRYPTION_KEY:
/opt/sub2api/
├── compose.yaml
├── data/
├── postgres_data/
└── redis_data/
/etc/sub2api/
├── sub2api.env
├── bootstrap-credentials.txt
└── managed-install
已有容器或数据目录不符合这套路径时,脚本会拒绝接管。先确认旧实例使用的镜像、挂载目录和数据库版本,再单独迁移;不要让新脚本猜测旧数据库密码或把未知数据卷当成可删除数据。
正式部署结束时会自动执行检查。需要重新运行时,在管理电脑上执行:
ssh -i "${SSH_KEY_PATH}" ubuntu@"${SERVER_IP}" \
'sudo bash /tmp/sub2api-provisioning/sub2api/verify-sub2api-host.sh \
--domain sub2api.example.com \
--acme-email admin@example.com'
如果部署时通过 --remote-dir 改过远端脚本目录,把命令中的 /tmp/sub2api-provisioning 换成实际路径。
命令会逐项检查以下状态:
- Caddy 正在监听 80/443,HTTPS
/health返回成功; docker port sub2api 8080/tcp只返回127.0.0.1:8080;- PostgreSQL 与 Redis 没有宿主机端口;
PGDATA、运行中的SHOW data_directory和宿主机 bind mount 指向同一份 PostgreSQL 数据;- Redis
PING返回PONG,三个容器的健康状态正常。
公网请求先到 Caddy 的 80/443,再由 Caddy 转给 127.0.0.1:8080。PostgreSQL 和 Redis 只在 Compose 私有网络中使用 5432 和 6379,不需要开放宿主机端口;Sub2API 访问 AI 服务时再通过出站 443 建立连接。
PGDATA 是 PostgreSQL 的启动声明,SHOW data_directory 是运行实例实际打开的位置,bind mount 则说明数据写到宿主机的哪个目录。三处必须指向同一份数据;只看容器显示 running 或只看挂载列表,都可能把空目录误认成正在使用的数据库。
这是一套单机部署。服务器、磁盘或 Caddy 停止工作时,整个入口都会中断。需要多实例时,PostgreSQL、Redis、会话状态和账号调度都要重新设计,不能直接复制第二套 Compose。
登录后台并修改管理员账号
初始管理员邮箱和密码保存在仅 root 可读的文件中:
sudo cat /etc/sub2api/bootstrap-credentials.txt
浏览器打开 https://sub2api.example.com。页面进入登录界面且证书有效,说明 DNS、Caddy 与本机 8080 端口之间已经接通。
首次登录后立即更换管理员密码,把新密码保存到密码管理器,再启用两步验证。恢复码只保存在离线位置,不要和服务器上的环境文件放在一起。
两个环境变量必须长期保持稳定:
| 变量 | 用途 | 被替换后的结果 |
|---|---|---|
JWT_SECRET | 签发登录会话 | 现有会话全部失效,所有用户需要重新登录 |
TOTP_ENCRYPTION_KEY | 加密两步验证密钥 | 已绑定的动态口令无法解密,用户无法完成 2FA 登录 |
日常重复部署不会覆盖这两个值。确实需要轮换 TOTP_ENCRYPTION_KEY 时,先解除或重建所有用户的两步验证,再替换密钥;顺序颠倒会直接锁住账号。
添加 AI 账号并测试连接
打开左侧的“账号管理”,点击右上角的“添加账号”。

在弹窗中填写一个便于识别的账号名称,再选择平台和账号类型。页面提供 OAuth 和 API Key 两种接入方式:账号支持 OAuth 时,选择 OAuth 并按“下一步”完成授权;使用平台 API Key 时,选择“API Key”并填写对应凭据。模型白名单和模型映射不是必填项,只在需要限定模型或替换模型名时设置。

账号保存后会回到账号管理列表。列表会显示平台、OAuth 或 API Key 类型、账号状态和已加入的分组;账号状态显示“正常”后,再把它加入分组。
创建分组并生成 API Key
账号提供可调用的模型,分组决定这些账号怎样对外使用,API Key 则把指定分组交给一台设备或一个程序。
创建分组并加入账号
打开左侧的“分组管理”,点击右上角的“创建分组”。

填写分组名称,选择与账号一致的平台。费率倍数决定用量按什么倍率计算;每分钟请求数填 0 时不限制,其他数值表示该分组每分钟允许的最大请求数。推理强度上限会限制这个分组可以使用的最高推理级别。

创建完成后,在分组列表的操作列点击“编辑”,把刚才状态正常的账号加入这个分组。账号数一列会显示可用、限流和总账号数;确认总数不再为 0 后,再为这个分组生成 API Key。
为客户端生成 API Key
打开左侧“我的账户”下的“API 密钥”,点击右上角的“创建密钥”。名称直接写用途,例如 macbook-codex 或 team-ci,再选择刚才创建的分组。

密钥生成后,列表会显示所属分组、并发数、用量和状态。把 Key 复制到对应客户端,不要写入 Git 仓库或公开截图。
使用 API Key 发起第一次请求
在 API 密钥列表的操作列点击“使用密钥”,Sub2API 会按 Codex CLI、Codex CLI WebSocket 或 OpenCode 生成配置。选择 macOS / Linux 或 Windows,再复制界面中的配置。

其他兼容 OpenAI 接口的客户端需要填写三项内容:
| 客户端字段 | 填写内容 |
|---|---|
| API 地址或 Base URL | https://sub2api.example.com/v1 |
| API Key | 后台刚生成的 Sub2API API Key |
| 模型 | 当前分组已经开放的模型 ID |
不同客户端的字段名称可能不同,但 API 地址都应指向你的 Sub2API 域名,而不是 OpenAI、Anthropic 或 Google 的官方地址。模型 ID 先从网关查询,不要照抄其他账号或旧配置。
先查询当前 Key 能看到的模型,避免把后台名称或旧配置直接写进请求:
export SUB2API_BASE_URL="https://sub2api.example.com/v1"
export SUB2API_API_KEY="<刚创建的 API Key>"
curl -fsS "${SUB2API_BASE_URL}/models" \
-H "Authorization: Bearer ${SUB2API_API_KEY}"
从返回结果中选一个分组允许的模型,再发起最短请求。不同 AI 平台支持的接口可能不同;下面使用 OpenAI Responses 路径:
export SUB2API_MODEL="<模型 ID>"
curl -fsS "${SUB2API_BASE_URL}/responses" \
-H "Authorization: Bearer ${SUB2API_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "'"${SUB2API_MODEL}"'",
"input": "Reply with: gateway ready"
}'
请求返回后,打开后台的用量记录,找到同一时间的 Key、模型和 Token 消耗。请求成功但没有对应记录时,先确认调用地址是网关域名,再检查 Key 所属分组和当前版本的计费设置。
检查错误 Key、未开放模型和停用状态
把 API Key 改成一个不存在的值,再请求一次 /models。Sub2API 应拒绝这次请求,后台也不应生成正常用量;如果仍能列出模型,客户端可能没有访问当前网关,或者域名前还有另一层认证代理。
换回有效 Key,再把模型改成当前分组没有开放的值。请求应直接失败,不能自动换成另一个模型。错误码和正文会随 Sub2API 版本、接口协议与账号类型变化,但未开放的模型不应返回正常内容,也不应产生一次正常用量。
最后停用测试 Key,再重放刚才成功的请求。停用后请求应被拒绝,不需要更换后台保存的 AI 账号。正式 Key 可以重新启用,测试 Key 则保持停用。
正式 Key 随后可以填进 Codex、Cherry Studio 或其他客户端。客户端只保存 Sub2API 的 Base URL 和 API Key,不需要保存后台账号的 OAuth 凭据或 AI 平台 API Key。
备份和升级 Sub2API
备份 Sub2API 数据和配置
备份前先停止 Sub2API、PostgreSQL 和 Redis,避免归档过程中数据继续写入。归档需要同时包含数据库、环境变量、Compose 配置和 Caddy 配置:
cd /opt/sub2api
sudo docker compose \
--env-file /etc/sub2api/sub2api.env \
-f compose.yaml stop sub2api postgres redis
backup="/var/backups/sub2api/sub2api-$(date -u +%Y%m%dT%H%M%SZ).tar.gz"
sudo install -d -m 700 /var/backups/sub2api
sudo tar -C / -czf "${backup}" \
opt/sub2api \
etc/sub2api \
etc/caddy \
var/lib/caddy
sudo sha256sum "${backup}" | sudo tee "${backup}.sha256"
sudo docker compose \
--env-file /etc/sub2api/sub2api.env \
-f compose.yaml start postgres redis sub2api
curl --fail --retry 30 --retry-delay 2 --retry-all-errors \
https://sub2api.example.com/health
将 .tar.gz 和 .sha256 一起复制到另一台主机或对象存储。两者只留在同一块系统盘时,系统盘损坏会同时丢失服务和备份。
使用固定版本升级 Sub2API
升级前查看目标版本的 Release Notes,确认数据库迁移和配置变化,并先运行上面的备份命令。然后把目标版本显式传给脚本:
export TARGET_VERSION="0.2.5" # 示例;执行前以 Releases 页面为准
bash deployments/scripts/sub2api/provision-sub2api-host.sh \
--host "${SERVER_IP}" \
--domain sub2api.example.com \
--ssh-user ubuntu \
--ssh-key "${SSH_KEY_PATH}" \
--sub2api-image "weishaw/sub2api:${TARGET_VERSION}"
不要用可变标签执行升级。新版本修改数据库后,只把应用镜像改回旧版本不会恢复旧数据;需要回退时,应使用升级前的备份。
Sub2API 无法访问或请求失败时怎么排查
后台打不开、Caddy 返回 502、API 返回 401、模型列表为空和请求超时,分别对应不同的检查位置:
| 症状 | 首先检查 | 处理方法 |
|---|---|---|
| HTTPS 无法打开 | DNS、80/443、安全组、caddy.service | 修正解析或放行规则,查看 journalctl -u caddy |
| Caddy 返回 502 | 127.0.0.1:8080/health、Sub2API 日志 | 根据日志修正应用配置,再重启 Sub2API |
| 后台可登录,API 返回 401 | Authorization 头、Key 状态、所属分组 | 重新复制正确 Key,启用 Key 或修正分组 |
/models 为空或缺模型 | 账号状态、分组平台和模型范围 | 确认账号状态正常,再调整分组 |
| 请求超时 | AI 平台连通性、代理、账号可调度状态 | 从服务器直接测试 AI 平台域名,修正代理或暂停异常账号 |
先在服务器执行这些命令,判断问题停在 Caddy、Sub2API 还是容器:
cd /opt/sub2api
sudo docker compose \
--env-file /etc/sub2api/sub2api.env \
-f compose.yaml ps
sudo docker compose \
--env-file /etc/sub2api/sub2api.env \
-f compose.yaml logs --tail 200 postgres redis sub2api
docker port sub2api 8080/tcp
curl -fsS http://127.0.0.1:8080/health
curl -fsS https://sub2api.example.com/health
sudo systemctl status caddy --no-pager
curl http://127.0.0.1:8080/health 失败时,先看 Sub2API 日志;本机健康但公网失败时,检查 Caddy、DNS 和 80/443;两处都正常而客户端仍然失败时,回到 API Key、分组和账号页面检查状态。