Sub2API 部署实战:Fedora + Podman,把多个模型渠道整合成一个 API
目录
起因:我不想再写一个中转脚本关于 Sub2API 的一个认知纠正架构第一步:装 Podman第二步:装 podman-compose(重点)路径 A:podman compose(原生插件)路径 B:podman-compose(Python 第三方包)podman compose vs podman-compose 的区别第三步:创建项目目录和配置文件创建 .env 文件创建 docker-compose.yml第四步:SELinux 处理(Fedora 必做)第五步:启动第六步:设置向导第七步:添加渠道第八步:验证踩坑记录坑 1:podman-compose restart 不重新加载配置坑 2:up -d 会重建容器,我的数据是不是丢了?坑 3:改了 compose 文件后,如何确认改动生效?坑 4:podman-compose 对 container_name 的处理运维速查开机自启内存占用总结写于部署过程中,记录真实的踩坑与解决方案。
起因:我不想再写一个中转脚本
我有好几个不同模型服务商的 API key——DeepSeek、智谱、阿里通义、OpenAI……每个渠道接口格式、base URL 都不一样。想在自己的应用里用,就得针对每个渠道写一套调用代码,改个模型还要到处改。
所以我想:能不能把这些渠道整合成一个统一的 API 入口,前端只对接一个端点,内部自动分发?
查了一圈发现两个候选:
- New API(QuantumNous/new-api):Go + PostgreSQL + Redis,需要搭三个组件,架构偏重
- Sub2API(Wei-Shaw/sub2api):Go 单二进制 + PostgreSQL + Redis,但 Go 进程本身很轻
我的服务器是 2 核 2G 的 Fedora,New API 需要 PostgreSQL + Redis + Go 三者同时在跑,2G 内存实在局促。Sub2API 是 Go 二进制,内存占用小得多,2G 绰绰有余,所以最终选了 Sub2API。
关于 Sub2API 的一个认知纠正
一开始我以为 Sub2API 只支持境外模型(Claude、OpenAI、Gemini),国产渠道不行。后来发现这个判断完全是错的。
Sub2API 添加上游渠道时,只需要填 base URL + API key,它走的是标准的 OpenAI 兼容协议。只要是 OpenAI 格式的接口——DeepSeek、智谱、阿里通义、火山引擎,全都可以接。它不挑服务商,是一个通用的 API 网关。
架构
Sub2API 需要 PostgreSQL 15+ 和 Redis 7+ 两个依赖,通过容器来跑:
┌──────────────┐
│ 你的应用 │
└──────┬───────┘
│ OpenAI 格式
▼
┌─────────────────┐
│ Sub2API │ 统一入口
│ (端口 8080) │ http://服务器IP:8080
└────────┬────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
DeepSeek 智谱/通义 OpenAI/Claude
第一步:装 Podman
Fedora 自带 Podman,直接确认版本:
podman --version第二步:装 podman-compose(重点)
这是最容易踩坑的一步。Podman 想用 Docker Compose 语法来管理多容器,有两条路:
路径 A:podman compose(原生插件)
通过 dnf 装 podman-plugins:
sudo dnf install -y podman-plugins
podman compose version # 命令是 "podman compose",没有连字符这是 Podman 官方内置的 compose 支持,是 Podman 子命令,性能更好,与 Podman 内核集成更紧密。
路径 B:podman-compose(Python 第三方包)
通过 pip 装:
pip install podman-compose
podman-compose --version # 命令是 "podman-compose",有连字符这是一个独立的 Python 程序,不是 Podman 的子命令。
我选的是路径 B(pip 安装),因为 dnf install podman-plugins 在我的系统上折腾了半天没装好。
podman compose vs podman-compose 的区别
虽然名字只差一个连字符,但它们是两个不同的东西:
| 对比项 | podman compose | podman-compose |
|---|---|---|
| 命令写法 | podman compose(子命令) | podman-compose(独立命令) |
| 安装方式 | dnf install podman-plugins | pip install podman-compose |
| 实现语言 | Go(Podman 原生) | Python |
| 本质 | Podman 内置功能 | 第三方封装,调用 Podman 底层 API |
| 性能 | 更快,直接和 Podman 内核对接 | 稍慢,经过 Python 中间层 |
| 功能覆盖 | 原生支持所有 Podman 特性 | 对 docker-compose.yml 语法兼容度高,但部分高级特性可能缺支持 |
| SELinux 处理 | 原生集成,自动处理 | 可能需要手动设置 SELinux 上下文 |
container_name | 完全支持 | 部分版本有兼容性差异 |
--compatibility 模式 | 默认更"Podman 化" | 默认更"Docker 兼容" |
最大的实际差异是命令写法。你看到教程写 docker compose up -d,换成 Podman 可能是 podman compose up -d(路径 A)或 podman-compose up -d(路径 B)。搜教程时经常被命令格式搞混。
如果你用 pip 装的,记住你的命令是
podman-compose(带连字符),不是podman compose。
第三步:创建项目目录和配置文件
mkdir -p ~/sub2api-deploy && cd ~/sub2api-deploy
mkdir -p data postgres_data redis_data创建 .env 文件
# 生成安全密钥
openssl rand -hex 32 # 输出一段随机字符串,复制下来
# 写入 .env
cat > .env << 'EOF'
POSTGRES_PASSWORD=你自己设的复杂密码
JWT_SECRET=刚才 openssl 生成的字符串
TOTP_ENCRYPTION_KEY=再用 openssl 生成一段
ADMIN_EMAIL=你的邮箱
ADMIN_PASSWORD=你的管理员密码
EOF创建 docker-compose.yml
version: "3.9"
services:
postgres:
image: docker.io/postgres:15-alpine
container_name: sub2api-postgres
restart: always
environment:
POSTGRES_DB: sub2api
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "127.0.0.1:5432:5432"
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: docker.io/redis:7-alpine
container_name: sub2api-redis
restart: always
ports:
- "127.0.0.1:6379:6379"
volumes:
- ./redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
sub2api:
image: ghcr.io/wei-shaw/sub2api:latest
container_name: sub2api
restart: always
ports:
- "0.0.0.0:8080:8080"
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- JWT_SECRET=${JWT_SECRET}
- TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY}
- ADMIN_EMAIL=${ADMIN_EMAIL}
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
- RUN_MODE=simple
- SIMPLE_MODE_CONFIRM=true
- SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP=false
volumes:
- ./data:/data
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy关于
RUN_MODE=simple:这是 Sub2API 的简易模式,隐藏 SaaS 计费功能,适合个人使用。如果后面想恢复标准模式(启用支付/计费),删掉RUN_MODE=simple和SIMPLE_MODE_CONFIRM=true这两行,然后podman-compose up -d重新拉起就行。
第四步:SELinux 处理(Fedora 必做)
Fedora 默认 SELinux 是 Enforcing 模式,容器挂载宿主机目录时会被拦截。先检查:
getenforce
# 如果输出 Enforcing,就需要处理给三个数据目录打标签:
sudo semanage fcontext -a -t container_file_t "$PWD/postgres_data(/.*)?"
sudo restorecon -Rv $PWD/postgres_data
sudo semanage fcontext -a -t container_file_t "$PWD/redis_data(/.*)?"
sudo restorecon -Rv $PWD/redis_data
sudo semanage fcontext -a -t container_file_t "$PWD/data(/.*)?"
sudo restorecon -Rv $PWD/data如果你用的是
podman-compose(pip 版),这一步尤其重要,因为它的 SELinux 自动处理能力不如原生podman compose。
第五步:启动
# 记住你的命令带连字符
podman-compose up -d
# 查看状态
podman-compose ps
# 查看日志
podman-compose logs -f sub2api第一次启动会拉取镜像,可能需要几分钟。
第六步:设置向导
浏览器访问 http://你的服务器IP:8080,进入设置向导:
- 数据库:主机
postgres,端口5432,用户postgres,密码填.env里设的 - Redis:主机
redis,端口6379 - 管理员:
.env里的邮箱和密码会自动填入
完成向导后就进入后台了。
第七步:添加渠道
进入后台 → Accounts → Add Account,选 API Key 类型。
各大渠道的 base URL:
| 渠道 | Base URL |
|---|---|
| DeepSeek | https://api.deepseek.com/v1 |
| 智谱 | https://open.bigmodel.cn/api/paas/v4 |
| 阿里通义 | https://dashscope.aliyuncs.com/compatible-mode/v1 |
| 火山引擎 | https://ark.cn-beijing.volces.com/api/v3 |
| OpenAI | https://api.openai.com/v1 |
| Anthropic | https://api.anthropic.com |
填好 base URL 和 API key,保存就行。多个渠道会自动做负载均衡和故障转移。
第八步:验证
curl http://你的服务器IP:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 你在后台生成的API Key" \
-d '{
"model": "deepseek-chat",
"messages": [{"role": "user", "content": "Hello"}]
}'能返回结果就说明整合成功了。
踩坑记录
坑 1:podman-compose restart 不重新加载配置
我发现改了 docker-compose.yml(比如删掉 RUN_MODE=simple),然后用 podman-compose restart sub2api,改动不生效。
原因是 restart 只是重启容器进程,不会重新读取 compose 文件。要加载新配置必须用 up -d:
# 错的:restart 只重启进程,不读新配置
podman-compose restart sub2api
# 对的:up -d 会重新加载 compose.yml 并重建容器
podman-compose up -d坑 2:up -d 会重建容器,我的数据是不是丢了?
第一次看到 up -d 把容器重建了,以为数据库和配置全没了。其实数据还在——PostgreSQL 和 Redis 的数据都在本地目录里:
~/sub2api-deploy/postgres_data/ ← 数据库
~/sub2api-deploy/redis_data/ ← 缓存
~/sub2api-deploy/data/ ← 应用数据
容器重建 ≠ 数据重建。up -d 只会重建改了配置的容器,没改的 PostgreSQL 和 Redis 容器不会动,数据目录也不动。
真正会把数据清掉的命令是
podman-compose down -v(带-v会删卷),平时只down不会。
坑 3:改了 compose 文件后,如何确认改动生效?
# 确认环境变量
podman exec sub2api env | grep -i "RUN_MODE\|SIMPLE"
# 如果输出为空,说明 simple 模式已经关了
# 确认日志
podman-compose logs sub2api | grep -i "mode"坑 4:podman-compose 对 container_name 的处理
podman-compose(pip 版)在启动带 container_name 的容器时,行为和原生 podman compose 有差异。如果看到容器名重复报错,检查一下是否有残留的旧容器:
podman ps -a --filter name=sub2api
# 有残留就删掉
podman rm -f sub2api sub2api-postgres sub2api-redis运维速查
cd ~/sub2api-deploy
# 查看状态
podman-compose ps
# 查看日志
podman-compose logs -f sub2api
# 重新加载配置并重建容器(改 compose 后必须用这个)
podman-compose up -d
# 仅重启容器进程(不改配置时用)
podman-compose restart sub2api
# 停止(不删数据)
podman-compose down
# 升级
podman-compose pull
podman-compose up -d
# 备份
podman-compose down
tar czf sub2api-backup-$(date +%Y%m%d).tar.gz .
podman-compose up -d开机自启
# 为每个容器生成 systemd 服务
for container in $(podman ps -a --format "{{.Names}}"); do
podman generate systemd --name $container --new --files
done
sudo mv container-*.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now container-sub2api-postgres
sudo systemctl enable --now container-sub2api-redis
sudo systemctl enable --now container-sub2api内存占用
| 组件 | 内存 |
|---|---|
| Sub2API(Go 二进制) | ~50-100 MB |
| PostgreSQL 15 Alpine | ~200-400 MB |
| Redis 7 Alpine | ~50-100 MB |
| 系统开销 | ~200 MB |
| 总计 | ~500-800 MB |
2G 内存完全够用,还有余量跑其他东西。
总结
Sub2API 的核心优势就是轻——Go 单二进制,2G 内存跑三个容器毫无压力。加上它对任意 OpenAI 兼容渠道的支持,把多个 API 渠道整合成一个端点这件事,确实省掉了自己写中转脚本的活儿。
唯一的小代价是需要搭 PostgreSQL + Redis 两个依赖,但用 Podman Compose 一行命令搞定,管理成本很低。