本指南基于当前 Go 代码库,详细说明各种部署方式。
- 前置要求
- 一、本地运行
- 二、Docker 部署
- 三、Vercel 部署
- 四、下载 Release 构建包
- 五、反向代理(Nginx)
- 六、Linux systemd 服务化
- 七、部署后检查
- 八、发布前进行本地回归
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| Go | 1.24+ | 编译后端 |
| Node.js | 20+ | 仅在需要本地构建 WebUI 时 |
| npm | 随 Node.js 提供 | 安装 WebUI 依赖 |
配置来源(任选其一):
- 文件方式:
config.json(推荐本地/Docker 使用) - 环境变量方式:
DS2API_CONFIG_JSON(推荐 Vercel 使用,支持 JSON 字符串或 Base64 编码) - 兼容写法:
CONFIG_JSON是旧版回退变量;DS2API_CONFIG_JSON也可以直接写原始 JSON
统一建议(最优实践):
cp config.example.json config.json
# 编辑 config.json建议把 config.json 作为唯一配置源:
- 本地运行:直接读
config.json - Docker / Vercel:从
config.json生成DS2API_CONFIG_JSON(Base64)注入环境变量
# 克隆仓库
git clone https://github.com/CJackHwang/ds2api.git
cd ds2api
# 复制并编辑配置
cp config.example.json config.json
# 使用你喜欢的编辑器打开 config.json,填入:
# - keys: 你的 API 访问密钥
# - accounts: DeepSeek 账号(email 或 mobile + password)
# 启动服务
go run ./cmd/ds2api默认监听 http://0.0.0.0:5001,可通过 PORT 环境变量覆盖。
本地首次启动时,若 static/admin/ 不存在,服务会自动尝试构建 WebUI(需要 Node.js/npm;缺依赖时会先执行 npm ci,再执行 npm run build -- --outDir static/admin --emptyOutDir)。
你也可以手动构建:
./scripts/build-webui.sh或手动执行:
cd webui
npm install
npm run build
# 产物输出到 static/admin/通过环境变量控制自动构建行为:
# 强制关闭自动构建
DS2API_AUTO_BUILD_WEBUI=false go run ./cmd/ds2api
# 强制开启自动构建
DS2API_AUTO_BUILD_WEBUI=true go run ./cmd/ds2apigo build -o ds2api ./cmd/ds2api
./ds2api# 复制环境变量模板
cp .env.example .env
# 编辑 .env(请改成你的强密码),至少设置:
# DS2API_ADMIN_KEY=your-admin-key
# 启动
docker-compose up -d
# 查看日志
docker-compose logs -f默认 docker-compose.yml 会把宿主机 6011 映射到容器内的 5001。如果你希望直接对外暴露 5001,请调整 ports 配置。
docker-compose up -d --buildDockerfile 提供两条构建路径:
- 本地/开发默认路径(
runtime-from-source):三阶段构建(WebUI 构建 + Go 构建 + 运行阶段)。 - Release 路径(
runtime-from-dist):CI 先生成dist/ds2api_<tag>_linux_<arch>.tar.gz,再由 Docker 直接复用该发布包内的二进制和static/admin产物组装运行镜像,不再重复执行npm build/go build。
Release 路径可确保 Docker 镜像与 release 压缩包使用同一套产物,减少重复构建带来的差异。
容器内启动命令:/usr/local/bin/ds2api,默认暴露端口 5001。
docker-compose -f docker-compose.dev.yml up开发模式特性:
- 源代码挂载(修改即生效)
LOG_LEVEL=DEBUG- 不自动重启
Docker Compose 已配置内置健康检查:
healthcheck:
test: ["CMD", "/usr/local/bin/busybox", "wget", "-qO-", "http://localhost:${PORT:-5001}/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s如果容器日志正常但面板打不开,优先检查:
- 端口是否一致:
PORT改成非5001时,访问地址也要改成对应端口(如http://localhost:8080/admin)。 - 开发 compose 的 WebUI 静态文件:
docker-compose.dev.yml使用go run开发镜像,不会在容器内自动安装 Node.js;若仓库里没有static/admin,/admin会返回 404。可先在宿主机构建一次:./scripts/build-webui.sh。
仓库提供 zeabur.yaml 模板,可在 Zeabur 上一键部署:
部署要点:
- 端口:服务默认监听
5001,模板会固定设置PORT=5001。 - 配置持久化:模板挂载卷
/data,并设置DS2API_CONFIG_PATH=/data/config.json;在管理台导入配置后,会写入并持久化到该路径。 - 构建版本号:Zeabur / 普通
docker build默认不需要传BUILD_VERSION;镜像会优先使用该构建参数,未提供时自动回退到仓库根目录的VERSION文件。 - 首次登录:部署完成后访问
/admin,使用 Zeabur 环境变量/模板指引中的DS2API_ADMIN_KEY登录(建议首次登录后自行更换为强密码)。
-
Fork 仓库到你的 GitHub 账号
-
在 Vercel 上导入项目
-
配置环境变量(最少只需设置以下一项):
变量 说明 DS2API_ADMIN_KEY管理密钥(必填) DS2API_CONFIG_JSON配置内容,JSON 字符串或 Base64 编码(可选,建议) -
部署
如果你想先完成一键部署,也可以先不填 DS2API_CONFIG_JSON,部署后进入 /admin 导入配置,再在「Vercel 同步」里写回环境变量。
建议先在仓库目录复制示例配置,再按实际账号填写:
cp config.example.json config.json
# 编辑 config.json不要在 Vercel 面板里手写复杂 JSON,建议本地生成 Base64 后粘贴:
# 在仓库根目录执行
DS2API_CONFIG_JSON="$(base64 < config.json | tr -d '\n')"
echo "$DS2API_CONFIG_JSON"如果你选择在部署前就预置配置,请在 Vercel Project Settings -> Environment Variables 配置:
DS2API_ADMIN_KEY=请替换为强密码
DS2API_CONFIG_JSON=上一步生成的一整行 Base64
可选但推荐(用于 WebUI 一键同步 Vercel 配置):
VERCEL_TOKEN=你的 Vercel Token
VERCEL_PROJECT_ID=prj_xxxxxxxxxxxx
VERCEL_TEAM_ID=team_xxxxxxxxxxxx # 个人账号可留空
| 变量 | 说明 | 默认值 |
|---|---|---|
DS2API_ACCOUNT_MAX_INFLIGHT |
每账号并发上限 | 2 |
DS2API_ACCOUNT_CONCURRENCY |
同上(兼容别名) | — |
DS2API_ACCOUNT_MAX_QUEUE |
等待队列上限 | recommended_concurrency |
DS2API_ACCOUNT_QUEUE_SIZE |
同上(兼容别名) | — |
DS2API_GLOBAL_MAX_INFLIGHT |
全局并发上限 | recommended_concurrency |
DS2API_MAX_INFLIGHT |
同上(兼容别名) | — |
DS2API_VERCEL_INTERNAL_SECRET |
混合流式内部鉴权 | 回退用 DS2API_ADMIN_KEY |
DS2API_VERCEL_STREAM_LEASE_TTL_SECONDS |
流式 lease TTL | 900 |
VERCEL_TOKEN |
Vercel 同步 token | — |
VERCEL_PROJECT_ID |
Vercel 项目 ID | — |
VERCEL_TEAM_ID |
Vercel 团队 ID | — |
DS2API_VERCEL_PROTECTION_BYPASS |
部署保护绕过密钥(内部 Node→Go 调用) | — |
请求 ─────┐
│
▼
vercel.json 路由规则
│
┌─────┴─────┐
│ │
▼ ▼
api/index.go api/chat-stream.js
(Go Runtime) (Node Runtime)
- 入口文件:
api/index.go(Serverless Go) - 流式入口:
api/chat-stream.js(Node Runtime,保证实时 SSE) - 路由重写:
vercel.json - 构建命令:
npm ci --prefix webui && npm run build --prefix webui(自动执行)
由于 Vercel Go Runtime 存在平台层响应缓冲,本项目在 Vercel 上采用"Go prepare + Node stream"的混合链路:
api/chat-stream.js收到/v1/chat/completions请求- Node 调用 Go 内部 prepare 接口(
?__stream_prepare=1),获取会话 ID、PoW、token 等 - Go prepare 创建 stream lease,锁定账号
- Node 直连 DeepSeek 上游,实时流式转发 SSE 给客户端(含 OpenAI chunk 封装与 tools 防泄漏筛分)
- 流结束后 Node 调用 Go release 接口(
?__stream_release=1),释放账号
该适配仅在 Vercel 环境生效;本地与 Docker 仍走纯 Go 链路。
api/chat-stream.js仅对非流式请求回退到 Go 入口(?__go=1)- 流式请求(包括带
tools)走 Node 路径,并执行与 Go 对齐的 tool-call 防泄漏处理 - WebUI 的"非流式测试"直接请求
?__go=1,避免 Node 中转造成长请求超时
vercel.json 已将 api/chat-stream.js 与 api/index.go 的 maxDuration 设为 300(受 Vercel 套餐上限约束)。
Error: Command failed: go build -ldflags -s -w -o .../bootstrap ...
原因:Vercel 项目的 Go 构建参数配置不正确(-ldflags 没有作为一个整体字符串传递)。
解决:
- 进入 Vercel Project Settings → Build and Development Settings
- 清空自定义 Go Build Flags / Build Command(推荐)
- 若必须设置 ldflags,使用
-ldflags="-s -w"(保证它是一个参数) - 确认仓库
go.mod为受支持版本(当前为go 1.24) - 重新部署(建议清缓存后 Redeploy)
use of internal package ds2api/internal/server not allowed
原因:Vercel Go 入口文件直接 import internal/...。
解决:当前仓库已通过公开桥接包 app 解决:api/index.go → ds2api/app → internal/server。
No Output Directory named "public" found after the Build completed.
解决:当前仓库使用 static 作为输出目录(vercel.json 中 "outputDirectory": "static")。若你在项目设置里手动改过 Output Directory,请设为 static 或清空让仓库配置生效。
如果接口返回 Vercel HTML 页面 Authentication Required:
- 方案 A:关闭该部署/环境的 Deployment Protection(推荐用于公开 API)
- 方案 B:请求中添加
x-vercel-protection-bypass头 - 方案 C:设置
VERCEL_AUTOMATION_BYPASS_SECRET(或DS2API_VERCEL_PROTECTION_BYPASS),仅影响内部 Node→Go 调用
static/admin目录不在 Git 中- Vercel / Docker 构建阶段自动生成 WebUI 静态文件
仓库内置 GitHub Actions 工作流:.github/workflows/release-artifacts.yml
- 触发条件:仅在 Release
published时触发(普通 push 不会构建) - 构建产物:多平台二进制压缩包 +
sha256sums.txt - 容器镜像发布:仅发布到 GHCR(
ghcr.io/cjackhwang/ds2api)
| 平台 | 架构 | 文件格式 |
|---|---|---|
| Linux | amd64, arm64 | .tar.gz |
| macOS | amd64, arm64 | .tar.gz |
| Windows | amd64 | .zip |
每个压缩包包含:
ds2api可执行文件(Windows 为ds2api.exe)static/admin/(WebUI 构建产物)sha3_wasm_bg.7b9ca65ddd.wasm(可选;程序内置 embed fallback)config.example.json、.env.exampleREADME.MD、README.en.md、LICENSE
# 1. 下载对应平台的压缩包
# 2. 解压
tar -xzf ds2api_<tag>_linux_amd64.tar.gz
cd ds2api_<tag>_linux_amd64
# 3. 配置
cp config.example.json config.json
# 编辑 config.json
# 4. 启动
./ds2api- 在 GitHub 创建并发布 Release(带 tag,如
vX.Y.Z) - 等待 Actions 工作流
Release Artifacts完成 - 在 Release 的 Assets 下载对应平台压缩包
# latest
docker pull ghcr.io/cjackhwang/ds2api:latest
# 指定版本(示例)
docker pull ghcr.io/cjackhwang/ds2api:v2.1.2如果在 Nginx 后部署,必须关闭缓冲以保证 SSE 流式响应正常工作:
location / {
proxy_pass http://127.0.0.1:5001;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
tcp_nodelay on;
}如果需要 HTTPS,可以在 Nginx 层配置 SSL 证书:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:5001;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
tcp_nodelay on;
}
}# 将编译好的二进制文件和相关文件复制到目标目录
sudo mkdir -p /opt/ds2api
sudo cp ds2api config.json /opt/ds2api/
# 可选:若你希望使用外置 WASM 文件(覆盖内置版本)
# sudo cp sha3_wasm_bg.7b9ca65ddd.wasm /opt/ds2api/
sudo cp -r static/admin /opt/ds2api/static/admin# /etc/systemd/system/ds2api.service
[Unit]
Description=DS2API (Go)
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/ds2api
Environment=PORT=5001
Environment=DS2API_CONFIG_PATH=/opt/ds2api/config.json
Environment=DS2API_ADMIN_KEY=your-admin-key-here
ExecStart=/opt/ds2api/ds2api
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target# 加载服务配置
sudo systemctl daemon-reload
# 设置开机自启
sudo systemctl enable ds2api
# 启动服务
sudo systemctl start ds2api
# 查看状态
sudo systemctl status ds2api
# 查看日志
sudo journalctl -u ds2api -f
# 重启服务
sudo systemctl restart ds2api
# 停止服务
sudo systemctl stop ds2api无论使用哪种部署方式,启动后建议依次检查:
# 1. 存活探针
curl -s http://127.0.0.1:5001/healthz
# 预期: {"status":"ok"}
# 2. 就绪探针
curl -s http://127.0.0.1:5001/readyz
# 预期: {"status":"ready"}
# 3. 模型列表
curl -s http://127.0.0.1:5001/v1/models
# 预期: {"object":"list","data":[...]}
# 4. 管理台页面(如果已构建 WebUI)
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:5001/admin
# 预期: 200
# 5. 测试 API 调用
curl http://127.0.0.1:5001/v1/chat/completions \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"hello"}]}'建议在发布前执行完整的端到端测试集(使用真实账号):
./tests/scripts/run-live.sh可自定义参数:
go run ./cmd/ds2api-tests \
--config config.json \
--admin-key admin \
--out artifacts/testsuite \
--timeout 120 \
--retries 2测试集自动执行内容:
- ✅ 语法/构建/单测 preflight
- ✅ 隔离副本配置启动服务(不污染原始
config.json) - ✅ 真实调用场景验证(OpenAI/Claude/Admin/并发/toolcall/流式)
- ✅ 全量请求与响应日志落盘(用于故障复盘)
详细测试集说明参阅 TESTING.md。