Skip to content

Latest commit

 

History

History
570 lines (405 loc) · 16 KB

File metadata and controls

570 lines (405 loc) · 16 KB

DS2API 部署指南

语言 / Language: 中文 | English

本指南基于当前 Go 代码库,详细说明各种部署方式。


目录


0. 前置要求

依赖 最低版本 说明
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)注入环境变量

一、本地运行

1.1 基本步骤

# 克隆仓库
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 环境变量覆盖。

1.2 WebUI 构建

本地首次启动时,若 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/ds2api

1.3 编译为二进制文件

go build -o ds2api ./cmd/ds2api
./ds2api

二、Docker 部署

2.1 基本步骤

# 复制环境变量模板
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 配置。

2.2 更新

docker-compose up -d --build

2.3 Docker 架构说明

Dockerfile 提供两条构建路径:

  1. 本地/开发默认路径(runtime-from-source:三阶段构建(WebUI 构建 + Go 构建 + 运行阶段)。
  2. 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

2.4 开发环境

docker-compose -f docker-compose.dev.yml up

开发模式特性:

  • 源代码挂载(修改即生效)
  • LOG_LEVEL=DEBUG
  • 不自动重启

2.5 健康检查

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

2.6 Docker 常见排查

如果容器日志正常但面板打不开,优先检查:

  1. 端口是否一致PORT 改成非 5001 时,访问地址也要改成对应端口(如 http://localhost:8080/admin)。
  2. 开发 compose 的 WebUI 静态文件docker-compose.dev.yml 使用 go run 开发镜像,不会在容器内自动安装 Node.js;若仓库里没有 static/admin/admin 会返回 404。可先在宿主机构建一次:./scripts/build-webui.sh

2.7 Zeabur 一键部署(Dockerfile)

仓库提供 zeabur.yaml 模板,可在 Zeabur 上一键部署:

Deploy on Zeabur

部署要点:

  • 端口:服务默认监听 5001,模板会固定设置 PORT=5001
  • 配置持久化:模板挂载卷 /data,并设置 DS2API_CONFIG_PATH=/data/config.json;在管理台导入配置后,会写入并持久化到该路径。
  • 构建版本号:Zeabur / 普通 docker build 默认不需要传 BUILD_VERSION;镜像会优先使用该构建参数,未提供时自动回退到仓库根目录的 VERSION 文件。
  • 首次登录:部署完成后访问 /admin,使用 Zeabur 环境变量/模板指引中的 DS2API_ADMIN_KEY 登录(建议首次登录后自行更换为强密码)。

三、Vercel 部署

3.1 部署步骤

  1. Fork 仓库到你的 GitHub 账号

  2. 在 Vercel 上导入项目

  3. 配置环境变量(最少只需设置以下一项):

    变量 说明
    DS2API_ADMIN_KEY 管理密钥(必填)
    DS2API_CONFIG_JSON 配置内容,JSON 字符串或 Base64 编码(可选,建议)
  4. 部署

3.1.1 推荐填写方式(避免 DS2API_CONFIG_JSON 填错)

如果你想先完成一键部署,也可以先不填 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   # 个人账号可留空

3.2 可选环境变量

变量 说明 默认值
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 调用)

3.3 Vercel 架构说明

请求 ─────┐
          │
          ▼
     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"的混合链路:

  1. api/chat-stream.js 收到 /v1/chat/completions 请求
  2. Node 调用 Go 内部 prepare 接口(?__stream_prepare=1),获取会话 ID、PoW、token 等
  3. Go prepare 创建 stream lease,锁定账号
  4. Node 直连 DeepSeek 上游,实时流式转发 SSE 给客户端(含 OpenAI chunk 封装与 tools 防泄漏筛分)
  5. 流结束后 Node 调用 Go release 接口(?__stream_release=1),释放账号

该适配仅在 Vercel 环境生效;本地与 Docker 仍走纯 Go 链路。

非流式回退与 Tool Call 处理

  • api/chat-stream.js 仅对非流式请求回退到 Go 入口(?__go=1
  • 流式请求(包括带 tools)走 Node 路径,并执行与 Go 对齐的 tool-call 防泄漏处理
  • WebUI 的"非流式测试"直接请求 ?__go=1,避免 Node 中转造成长请求超时

函数时长

vercel.json 已将 api/chat-stream.jsapi/index.gomaxDuration 设为 300(受 Vercel 套餐上限约束)。

3.4 Vercel 常见报错排查

Go 构建失败

Error: Command failed: go build -ldflags -s -w -o .../bootstrap ...

原因:Vercel 项目的 Go 构建参数配置不正确(-ldflags 没有作为一个整体字符串传递)。

解决

  1. 进入 Vercel Project Settings → Build and Development Settings
  2. 清空自定义 Go Build Flags / Build Command(推荐)
  3. 若必须设置 ldflags,使用 -ldflags="-s -w"(保证它是一个参数)
  4. 确认仓库 go.mod 为受支持版本(当前为 go 1.24
  5. 重新部署(建议清缓存后 Redeploy)

Internal 包导入错误

use of internal package ds2api/internal/server not allowed

原因:Vercel Go 入口文件直接 import internal/...

解决:当前仓库已通过公开桥接包 app 解决:api/index.gods2api/appinternal/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 调用

3.5 仓库不提交构建产物

  • static/admin 目录不在 Git 中
  • Vercel / Docker 构建阶段自动生成 WebUI 静态文件

四、下载 Release 构建包

仓库内置 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.example
  • README.MDREADME.en.mdLICENSE

使用步骤

# 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

维护者发布步骤

  1. 在 GitHub 创建并发布 Release(带 tag,如 vX.Y.Z
  2. 等待 Actions 工作流 Release Artifacts 完成
  3. 在 Release 的 Assets 下载对应平台压缩包

拉取 GHCR 镜像(可选)

# latest
docker pull ghcr.io/cjackhwang/ds2api:latest

# 指定版本(示例)
docker pull ghcr.io/cjackhwang/ds2api:v2.1.2

五、反向代理(Nginx)

如果在 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;
    }
}

六、Linux systemd 服务化

6.1 安装

# 将编译好的二进制文件和相关文件复制到目标目录
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

6.2 创建 systemd 服务文件

# /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

6.3 常用命令

# 加载服务配置
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