Skip to content

Docker 部署 Sub2API:搭建多模型订阅 API 网关

Claude、OpenAI、Gemini、Grok 等服务各有认证方式和调用协议。Sub2API 把这些账号接入、请求转发、配额与用户管理集中到一个后台,对外提供统一的 API 网关。

这套部署固定使用 2026 年 8 月 25 日发布的 0.1.183 镜像,运行 Sub2API、PostgreSQL 18 和 Redis 8 三个容器。数据保存在部署目录中,适合单台 Linux 服务器长期自托管,也方便整目录迁移。

Sub2API 会处理上游账号、OAuth 凭据和 API Key。部署者需要遵守对应服务商的账号、订阅和共享规则,不要把管理后台或原始凭据暴露给不受信任的用户。

部署结论

项目本文采用的值
GitHub 地址Wei-Shaw/sub2api
官方镜像weishaw/sub2api:0.1.183
Sub2API 版本0.1.183,对应 Git 标签 v0.1.183
部署方式Docker Compose,本地目录持久化版
适用范围单机、自托管、长期运行
主机架构linux/amd64linux/arm64
最低资源官方没有给出统一最低配置;容量取决于并发量、数据库和日志规模
对外端口宿主机 8080 → Sub2API 容器 8080
持久化目录./data./postgres_data./redis_data
依赖服务PostgreSQL 18-alpine、Redis 8-alpine
验证范围官方配置与发布记录核对;Compose 静态解析
资料核对日期2026-08-26

官方同时提供命名卷版 docker-compose.yml,但部署文档明确推荐 docker-compose.local.yml:三个数据目录都能直接看到,备份、搬迁和故障恢复更直观。本文只展开这条路径。

三个容器怎么配合

Mermaid 流程图
查看源码
flowchart LR
  client["API 客户端 / 管理员浏览器"] -->|"HTTP 8080;公网建议 HTTPS"| app["Sub2API 0.1.183"]
  app -->|"内部网络 5432"| pg[("PostgreSQL 18")]
  app -->|"内部网络 6379"| redis[("Redis 8")]
  app --> appdata["./data"]
  pg --> pgdata["./postgres_data"]
  redis --> redisdata["./redis_data"]

只有 Sub2API 的 8080 端口映射到宿主机。PostgreSQL 和 Redis 不对外开放端口,应用通过 Compose 创建的 sub2api-network 访问它们。Sub2API 会等待数据库和缓存通过健康检查后再启动,并通过 /health 检查自身状态。

部署前检查

官方中文说明要求 Docker 20.10+ 和 Docker Compose v2。服务器还需要 curlopenssl:前者下载版本固定的部署文件,后者生成不会出现在文章里的随机密钥。

bash
docker --version
docker compose version
curl --version
openssl version

确认宿主机的 8080 端口没有被占用:

bash
ss -lntp | grep ':8080 ' || true

如果这里已有监听进程,可以在后面的 .env 中修改 SERVER_PORT。容器内部端口仍然保持 8080

下载版本固定的部署文件

部署目录使用 /opt/sub2api。下面的 URL 指向 v0.1.183 标签,不会随 main 分支更新而改变。

bash
sudo mkdir -p /opt/sub2api
sudo chown "$(id -u):$(id -g)" /opt/sub2api
cd /opt/sub2api

curl -fL --retry 3 \
  -o compose.yaml \
  https://raw.githubusercontent.com/Wei-Shaw/sub2api/v0.1.183/deploy/docker-compose.local.yml

curl -fL --retry 3 \
  -o .env.example \
  https://raw.githubusercontent.com/Wei-Shaw/sub2api/v0.1.183/deploy/.env.example

官方 Compose 文件默认跟随浮动标签。把它替换为本文核对过的版本,再检查三个镜像引用:

bash
sed -i 's#weishaw/sub2api:latest#weishaw/sub2api:0.1.183#' compose.yaml
grep -n 'image:' compose.yaml

输出应包含:

text
weishaw/sub2api:0.1.183
postgres:18-alpine
redis:8-alpine

仓库里的 deploy/DOCKER.md 还保留了一份简化示例,其中数据库和缓存版本较旧。本文以 v0.1.183 标签下可执行的 docker-compose.local.yml 为准,没有混用那份旧示例。

生成环境变量和密钥

Compose 真正强制要求的是 POSTGRES_PASSWORDJWT_SECRET 为空时,每次启动会生成新值,现有登录会话随之失效;TOTP_ENCRYPTION_KEY 为空则会让已经绑定的双因素认证失效。因此这三个值都应该在第一次启动前固定下来。

下面还为 Redis 和管理员账号生成独立密码。所有随机值只写入当前目录的 .env,不会打印到终端。

bash
cd /opt/sub2api
umask 077

POSTGRES_PASSWORD="$(openssl rand -hex 32)"
REDIS_PASSWORD="$(openssl rand -hex 32)"
JWT_SECRET="$(openssl rand -hex 32)"
TOTP_ENCRYPTION_KEY="$(openssl rand -hex 32)"
ADMIN_PASSWORD="$(openssl rand -hex 24)"

cat > .env <<EOF
BIND_HOST=0.0.0.0
SERVER_PORT=8080
SERVER_MODE=release
RUN_MODE=standard
TZ=Asia/Shanghai

POSTGRES_USER=sub2api
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
POSTGRES_DB=sub2api

REDIS_PASSWORD=${REDIS_PASSWORD}
REDIS_DB=0

ADMIN_EMAIL=admin@sub2api.local
ADMIN_PASSWORD=${ADMIN_PASSWORD}

JWT_SECRET=${JWT_SECRET}
JWT_EXPIRE_HOUR=24
TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY}
EOF

chmod 600 .env
unset POSTGRES_PASSWORD REDIS_PASSWORD JWT_SECRET TOTP_ENCRYPTION_KEY ADMIN_PASSWORD

ADMIN_EMAIL 可以换成自己的管理邮箱。公网部署不建议长期使用 admin@sub2api.local,但不要把真实账号和密钥写进准备公开的教程、截图或代码仓库。

查看管理员密码时只在服务器本机执行:

bash
grep '^ADMIN_PASSWORD=' /opt/sub2api/.env

创建数据目录并检查 Compose

bash
cd /opt/sub2api
mkdir -p data postgres_data redis_data backups

docker compose --env-file .env -f compose.yaml config --quiet
docker compose --env-file .env -f compose.yaml config --images

第一条命令没有输出并返回状态码 0,说明环境变量和 Compose 语法能够正确展开。第二条命令应列出固定版本的 Sub2API、PostgreSQL 18 和 Redis 8。

不要在配置检查前启动容器。POSTGRES_PASSWORD 缺失时,官方 Compose 会直接报错并终止;这是为了避免数据库以错误凭据初始化。

启动 Sub2API

bash
cd /opt/sub2api
docker compose --env-file .env -f compose.yaml pull
docker compose --env-file .env -f compose.yaml up -d
docker compose --env-file .env -f compose.yaml ps

PostgreSQL 和 Redis 会先启动。两者健康后,Sub2API 执行自动初始化:连接依赖服务、应用数据库迁移、创建管理员账号,并在 ./data 中生成配置。

用有界日志查看最近的初始化结果,避免把持续跟随日志的命令留在无人值守终端里:

bash
docker compose --env-file .env -f compose.yaml logs --tail=150 sub2api

验证部署结果

容器和健康状态

bash
cd /opt/sub2api
docker compose --env-file .env -f compose.yaml ps
curl -fsS http://127.0.0.1:8080/health && echo

三个容器都应处于运行状态,Sub2API 最终应显示为 healthy。健康接口返回成功状态后,才继续配置上游账号。

PostgreSQL 与 Redis

bash
docker compose --env-file .env -f compose.yaml exec -T postgres \
  pg_isready -U sub2api -d sub2api

docker compose --env-file .env -f compose.yaml exec -T redis \
  redis-cli ping

数据库应报告 accepting connections,Redis 应返回 PONG。Redis 容器通过 REDISCLI_AUTH 读取 .env 中的密码,不需要把密码放进命令行。

数据库迁移记录

bash
docker compose --env-file .env -f compose.yaml exec -T postgres \
  psql -U sub2api -d sub2api -c \
  'SELECT filename, applied_at FROM schema_migrations ORDER BY filename DESC LIMIT 5;'

官方部署说明指出,迁移文件按文件名顺序执行,并将文件名与校验和记录到 schema_migrations。能查到记录,说明初始化不只是容器启动成功,数据库结构也已经落地。

宿主机持久化目录

bash
du -sh data postgres_data redis_data
find data -maxdepth 2 -type f -print | head -20

docker compose restart sub2api 不会删除这些目录。不要用删除容器或重启成功来代替备份恢复测试;持久化只说明数据路径存在。

首次登录和最小配置

在服务器本机打开 http://127.0.0.1:8080。从其他电脑访问时,使用 http://服务器实际IP:8080,同时把防火墙来源限制在可信 IP;公网长期运行应先完成后面的 HTTPS 和源站隔离。

使用 .env 中的 ADMIN_EMAILADMIN_PASSWORD 登录。Docker Compose 设置了 AUTO_SETUP=true,这条部署路径不需要再走 Web Setup Wizard。

登录后按实际用途添加 Claude、OpenAI、Gemini 或其他上游账号。OAuth Client Secret、刷新令牌和 API Key 都属于高敏感数据:不要放进公共仓库,也不要出现在管理后台截图中。

日常管理

bash
cd /opt/sub2api

# 查看状态
docker compose --env-file .env -f compose.yaml ps

# 查看最近 100 行应用日志
docker compose --env-file .env -f compose.yaml logs --tail=100 sub2api

# 只重启应用,不中断数据库和 Redis
docker compose --env-file .env -f compose.yaml restart sub2api

# 停止整套服务,保留数据目录
docker compose --env-file .env -f compose.yaml stop

# 重新启动
docker compose --env-file .env -f compose.yaml start

应用日志还会写入 ./data/logs/。官方 .env.example 默认启用滚动:单文件 100 MB、保留 10 个历史文件、历史日志保留 7 天并压缩。磁盘较小时应同步调整这些参数并监控目录占用。

备份与恢复

整目录压缩适合搬迁,但数据库正在写入时直接打包 postgres_data 不能替代 PostgreSQL 原生备份。下面先停止应用写入,再分别备份数据库、Redis 和应用文件。

bash
cd /opt/sub2api
STAMP="$(date +%Y%m%d-%H%M%S)"

docker compose --env-file .env -f compose.yaml stop sub2api

docker compose --env-file .env -f compose.yaml exec -T postgres \
  pg_dump -U sub2api -d sub2api -Fc \
  > "backups/postgres-${STAMP}.dump"

docker compose --env-file .env -f compose.yaml exec -T redis \
  redis-cli SAVE

tar --exclude='./backups' -czf "backups/state-${STAMP}.tar.gz" \
  compose.yaml .env data redis_data

docker compose --env-file .env -f compose.yaml start sub2api

sha256sum "backups/postgres-${STAMP}.dump" \
  "backups/state-${STAMP}.tar.gz" \
  > "backups/checksums-${STAMP}.txt"

.env 包含数据库、Redis、JWT、TOTP 和管理员密钥。备份文件应加密后再复制到另一台机器或对象存储,访问权限不能比生产服务器更宽。

恢复演练应放在另一台测试主机。官方 Compose 使用了固定容器名,同一台 Docker 主机上直接启动第二套配置会与生产容器冲突。先把状态归档和数据库备份复制到测试主机,核对校验和,再执行:

bash
read -r -p "状态归档的绝对路径: " STATE_ARCHIVE
read -r -p "PostgreSQL 备份的绝对路径: " POSTGRES_DUMP
test -f "$STATE_ARCHIVE" && test -f "$POSTGRES_DUMP"

sudo mkdir -p /opt/sub2api-restore
sudo chown "$(id -u):$(id -g)" /opt/sub2api-restore
cd /opt/sub2api-restore

tar -xzf "$STATE_ARCHIVE"
mkdir -p postgres_data backups
cp "$POSTGRES_DUMP" backups/restore.dump

docker compose --env-file .env -f compose.yaml up -d postgres redis
docker compose --env-file .env -f compose.yaml ps

等 PostgreSQL 和 Redis 都显示为 healthy 后,把逻辑备份恢复到测试数据库:

bash
cd /opt/sub2api-restore
docker compose --env-file .env -f compose.yaml exec -T postgres \
  pg_restore -U sub2api -d sub2api \
  --clean --if-exists --no-owner --no-privileges \
  < backups/restore.dump

docker compose --env-file .env -f compose.yaml up -d sub2api
docker compose --env-file .env -f compose.yaml ps
curl -fsS http://127.0.0.1:8080/health && echo

最后检查迁移记录、管理员登录、账号配置和一条低成本 API 请求。数据库恢复会改写目标库;生产库不要用作第一次恢复演练,也不要在验证完成前切换流量。

升级与回滚

Sub2API 的数据库迁移是 forward-only。升级后如果新版本写入了不可逆结构,单纯把镜像标签改回旧版并不构成完整回滚。

升级前先执行上一节的备份,然后设置目标版本:

bash
cd /opt/sub2api
cp compose.yaml compose.yaml.pre-upgrade

read -r -p "目标版本(不含 v): " TARGET_VERSION
test -n "$TARGET_VERSION"
docker manifest inspect "weishaw/sub2api:${TARGET_VERSION}" > /dev/null

sed -i -E \
  "s#weishaw/sub2api:[^[:space:]]+#weishaw/sub2api:${TARGET_VERSION}#" \
  compose.yaml

docker compose --env-file .env -f compose.yaml config --quiet
docker compose --env-file .env -f compose.yaml pull sub2api
docker compose --env-file .env -f compose.yaml up -d sub2api
docker compose --env-file .env -f compose.yaml logs --tail=150 sub2api

输入已经发布并完成资料核对的实际版本,随后阅读对应 Release Notes。验收失败时,停止新应用,恢复升级前 PostgreSQL 备份和状态文件,再使用 compose.yaml.pre-upgrade 启动旧镜像。没有数据库备份时,不要把回退镜像描述成安全回滚。

公网部署需要补上的防护

直接把 8080 暴露到公网只适合短期验证。长期运行至少处理下面几项:

  • .envBIND_HOST 改为 127.0.0.1,重新创建 Sub2API 容器,让源站只接受本机反向代理连接。
  • 使用 Nginx、Caddy 或 CDN 提供 HTTPS,并把防火墙入口限制到 80/443 或可信代理地址。
  • Sub2API 存在长时间 SSE 与 WebSocket 请求。反向代理需要关闭响应缓冲,保留 Upgrade 头,并把读写超时设置到能覆盖长生成任务的范围。
  • 不要压缩 text/event-stream。压缩和缓冲都可能让流式输出积压到请求结束才返回。
  • 只有反向代理确实覆盖并清洗转发头时,才信任 X-Forwarded-ForX-Real-IP 或 CDN 客户端 IP 头;同时阻止用户绕过代理直连源站。
  • 固定镜像版本,定期验证 PostgreSQL 备份可恢复,并对 data/logs、数据库和宿主机磁盘设置监控。

项目提供了专门的 Edge and HTTP Ingress Security 文档,里面给出了适配 SSE、WebSocket、256 MiB 请求体和可信代理链的 Nginx/Caddy 基线。不要用普通静态网站的短超时代理配置直接替代。

镜像拉取受限时怎么处理

本文保留官方 Docker Hub 镜像。0.1.183 Release 同时公布了官方 GHCR 地址,Docker Hub 拉取失败时可以把 Compose 中的应用镜像替换为:

text
ghcr.io/wei-shaw/sub2api:0.1.183
bash
sed -i \
  's#weishaw/sub2api:0.1.183#ghcr.io/wei-shaw/sub2api:0.1.183#' \
  compose.yaml
docker compose --env-file .env -f compose.yaml pull sub2api

这只是官方仓库之间的切换,不保证所有中国大陆网络都能稳定访问。本文没有把未经本次核验的公共镜像代理写成推荐地址。完全离线时,可以在联网机器拉取这三个固定版本镜像,用 docker save 导出,传输后校验文件 SHA-256,再在服务器执行 docker load

常见问题

Sub2API 容器反复重启并提示 exec format error

项目 Issue #2061 记录过 docker-entrypoint.sh: exec format error。该 issue 没有给出维护者确认的统一根因,先核对主机和镜像架构,不要直接改入口脚本:

bash
uname -m
docker image inspect weishaw/sub2api:0.1.183 \
  --format '{{.Architecture}}/{{.Os}}'
docker compose --env-file .env -f compose.yaml logs --tail=100 sub2api

官方镜像文档声明支持 linux/amd64linux/arm64。架构不匹配或旧镜像残留时,删除有问题的单个标签后重新拉取固定版本,不要执行全局镜像清理。

修改 Redis 密码后没有生效

Issue #2511 描述过更新 .env 后 Redis 容器没有按预期应用密码的情况。当前 v0.1.183 Compose 已在启动命令中根据 REDIS_PASSWORD 追加 --requirepass,但修改密码后仍应强制重建 Redis 和应用容器:

bash
docker compose --env-file .env -f compose.yaml up -d \
  --force-recreate redis sub2api

docker compose --env-file .env -f compose.yaml exec -T redis \
  redis-cli ping

不要只运行 docker compose restart;重启沿用原容器配置,不负责重新解析所有配置变化。

PostgreSQL 报 Operation not permitted

本地目录版已经给 PostgreSQL 挂载添加了 SELinux :Z 标签。出现权限错误时,先检查目录所有权、SELinux 审计日志和 Docker/内核版本:

bash
ls -ld postgres_data
docker compose --env-file .env -f compose.yaml logs --tail=100 postgres

Issue #6099 报告某些 CentOS 内核在默认 seccomp 下仍会失败,并用 seccomp:unconfined 绕过。但这会关闭容器系统调用过滤,issue 本身也把它标记为高风险。它只能作为隔离环境中的诊断手段,不能直接写入长期生产配置;更稳妥的处理是升级受支持的内核和 Docker,或改用命名卷验证问题是否来自宿主机绑定目录。

应用健康检查一直失败

bash
docker compose --env-file .env -f compose.yaml ps
docker compose --env-file .env -f compose.yaml logs --tail=150 sub2api
docker compose --env-file .env -f compose.yaml exec -T postgres \
  pg_isready -U sub2api -d sub2api
docker compose --env-file .env -f compose.yaml exec -T redis \
  redis-cli ping

Sub2API 依赖 PostgreSQL 和 Redis 健康后才启动。优先检查 .env 中的数据库密码、数据目录权限和迁移日志;不要反复删除数据目录来尝试“重新初始化”。

部署完成后

部署通过后,先完成 HTTPS、源站隔离和异地备份,再接入真实上游账号。随后创建一个低权限测试用户和独立 API Key,用一次小请求验证认证、路由、用量记录和流式响应;管理账号不要直接交给普通调用方使用。

总结

本文以 Sub2API 0.1.183 的版本固定 Compose 文件为基础,给出单机自托管所需的密钥生成、持久化、健康检查、数据库备份、恢复演练和升级边界。文章完成了官方资料核对与 Compose 静态解析,但没有在当前环境拉取镜像或启动容器;正式接入真实上游账号前,仍需在目标服务器验证 HTTPS、源站隔离、备份恢复和一条低成本 API 请求。

参考资料

全部公开文章由同一个站点构建和发布。