Spaces:
Running
部署文档(Hugging Face Spaces)
本文档说明如何把 XTC 后端部署到 Hugging Face Spaces,采用混合存储方案:本地 SQLite 持久卷(热存储)+ HF Hub dataset 仓库(配置备份)。
存储方案说明:本项目采用混合方案——
- 主体数据(令牌、会话、请求历史、用量、审计、速率限制、Webhook)存在 HF Spaces 本地的
/data/xtc.db(SQLite)- 配置文件(providers / 默认厂商)额外同步到 HF Hub dataset 仓库做备份
为什么配置要走 Hub? HF Spaces 免费档磁盘是 ephemeral(临时),restart/stop 会清空
/data,导致配置丢失。把配置 JSON 备份到 HF Hub dataset 仓库(随账号持久保存),重建后能自动拉取恢复。其余数据(会话/日志等)反正不重启也无所谓,纯本地即可。付费档用户($5/月 Small 持久存储):
/data永久保留,可不配置 Hub 备份(但配了也无妨,多一层保险)。
一、整体架构
手表端 / 前端
│ HTTPS
▼
Cloudflare Workers(反向代理,可选)
│ 解决:免费域名 / 国内访问 / 48h 休眠保活
▼
Hugging Face Spaces(Docker 类型)
│ 运行 FastAPI + uvicorn
▼
/data/xtc.db(SQLite 持久卷)
│
├─ config 配置(providers / 默认厂商)──┐ 备份
├─ access_tokens 临时令牌 │
├─ sessions 会话历史 │
├─ session_messages 会话消息 │
├─ request_log 请求历史(最近 N 条) │ 仅配置
├─ usage_log 用量统计 │ 走 Hub
├─ audit_log 审计日志 │
├─ rate_limit 速率限制 │
└─ webhook_config Webhook 配置 │
▼
HF Hub dataset 仓库(config/app_config.json)
解决免费档 ephemeral 问题,重建后自动恢复配置
为什么仅配置走 Hub,其余纯本地?
- 单实例部署,Hub 的"多实例同步"优势用不上,避免无谓的网络开销
- 本地 SQLite 读写比网络 API 快几个数量级
- 配置是唯一"丢了很麻烦"的数据(要重新填所有 API Key),其余数据(日志/会话)重建丢失可接受
- 图片/文件前端会重传,不需要后端长期存储
- 复杂度可控:只在
config_store一处接入 Hub,其余模块无感知
持久性保证:
- HF Spaces 免费档:restart/stop 清空
/data,但配置已备份到 Hub,重建后自动恢复 - HF Spaces 付费档($5/月):
/data永久保留,所有数据都不丢 - 删除整个 Space:
/data丢失,但 Hub 仓库里的配置备份仍在
二、前置准备
1. 注册 Hugging Face 账号
访问 https://huggingface.co/join 注册(免费)。
2. 准备代码仓库
本项目代码在 GitHub 仓库 luckfun233/AI 的 xtc-backend-hf/ 目录。HF Spaces 支持两种方式同步代码:
- 方式 A(推荐):HF Space 直接从 GitHub 同步(每次 push 自动重建)
- 方式 B:手动把代码推到 HF Space 的 Git 仓库
三、创建 HF Space
1. 新建 Space
- 访问 https://huggingface.co/new-space
- 填写:
- Space name:
xtc-backend(或任意名) - License:随意
- SDK:选择 Docker
- Space hardware:**CPU basic (Free)**(免费档够用)
- Visibility:Private(强烈建议私有,避免后台暴露)
- Space name:
- 点击 Create Space
2. 绑定持久化存储(可选,付费档)
免费档磁盘是 ephemeral(临时),restart/stop 会清空 /data。本项目通过 HF Hub 仓库备份配置来规避此问题(见下一步),所以免费档也能用。
如需所有数据(会话/日志等)都持久保留,可开通付费持久存储:
- 进入刚创建的 Space
- 点击顶部 Settings 标签
- 找到 Persistent storage 区域
- 选择容量(20 GB Small - $5/month,最小档够用)
- 点击 Attach 并完成支付
免费档 vs 付费档:
- 免费档:配置靠 Hub 备份(不丢),其余数据 restart/stop 后清空(可接受)
- 付费档:所有数据永久保留,Hub 备份作为额外保险
3. 创建 HF Hub 配置备份仓库(免费档强烈建议)
用于备份配置文件,解决免费档磁盘 ephemeral 问题:
- 访问 https://huggingface.co/new-dataset
- 填写:
- Dataset name:
xtc-config(或任意名) - License:随意
- Visibility:Private(强烈建议私有,配置含 API Key)
- Dataset name:
- 点击 Create dataset
记录仓库名称,格式为 用户名/xtc-config(如 luckfun233/xtc-config),后面配置 HF_CONFIG_REPO 要用。
4. 创建 HF Access Token
用于后端读写配置备份仓库:
- 访问 https://huggingface.co/settings/tokens
- 点击 New token
- 填写 Name(如
xtc-backend),Type 选 Write(需要写权限推送配置) - 复制 token(以
hf_开头),后面配置HF_TOKEN要用
权限说明:token 需要对上一步创建的 dataset 仓库有 write 权限。Space 和 dataset 在同一账号下时,Write token 自动有权限。
5. 同步代码
方式 A:从 GitHub 同步(推荐)
- Space Settings → Repositories → Connect a GitHub repository
- 选择
luckfun233/AI仓库 - Root directory 填写:
xtc-backend-hf - 保存后,每次 GitHub push 自动触发 HF 重建
方式 B:手动推送
# 在 HF 账号设置里创建 Access Token:https://huggingface.co/settings/tokens
# 权限选 Write,复制 token
cd xtc-backend-hf
git init
git remote add hf https://<你的HF用户名>:<HF_TOKEN>@huggingface.co/spaces/<你的HF用户名>/xtc-backend
git add .
git commit -m "init"
git push hf main
四、配置环境变量
这是最关键的一步。在 Space Settings → Variables and secrets 中添加以下环境变量:
必填(不填无法正常运行)
| 变量名 | 说明 | 示例值 |
|---|---|---|
XTC_ADMIN_KEY |
后台管理密钥,访问 /admin 登录用 |
my-super-admin-key-2026 |
XTC_ACCESS_KEY |
前端/手表端长期访问密钥 | my-access-key-for-watch |
XTC_JWT_SECRET |
JWT 签名密钥(临时令牌),必须随机长字符串 | a1b2c3d4e5...(32位以上随机) |
生成随机密钥:在本地终端运行
openssl rand -hex 32生成XTC_JWT_SECRET。
选填(有默认值,通常不用改)
| 变量名 | 默认值 | 说明 |
|---|---|---|
PORT |
7860 |
服务端口(HF Spaces 固定 7860,不要改) |
XTC_DB_PATH |
/data/xtc.db |
SQLite 数据库路径(持久卷路径,不要改) |
XTC_DISABLE_ADMIN |
false |
紧急关闭后台(设 true 则 /admin 不可用) |
UPSTREAM_TIMEOUT_MS |
120000 |
上游 API 超时(毫秒) |
XTC_ACCESS_TOKEN_TTL_SEC |
1800 |
临时令牌有效期(秒,60-86400) |
XTC_ACCESS_TOKEN_LENGTH |
8 |
临时令牌长度(6-24) |
选填(种子厂商,也可启动后在后台配)
| 变量名 | 说明 |
|---|---|
GEMINI_API_KEY |
Gemini API 密钥(可填多个,逗号分隔) |
OPENAI_API_KEY |
OpenAI 兼容厂商的 API 密钥 |
OPENAI_BASE_URL |
OpenAI 兼容厂商的 base URL(默认 https://api.openai.com) |
建议:
GEMINI_API_KEY/OPENAI_API_KEY留空,启动后用/admin后台添加厂商,这样密钥存在 SQLite 而非环境变量里,方便随时增删轮询。
选填(HF Hub 配置备份,免费档强烈建议)
| 变量名 | 说明 | 示例值 |
|---|---|---|
HF_TOKEN |
HF Hub 访问令牌(write 权限,见第三节第 4 步) | hf_xxxxxxxxxxxxxxxxxxxx |
HF_CONFIG_REPO |
配置备份 dataset 仓库名(见第三节第 3 步) | luckfun233/xtc-config |
配置后才生效:两个变量都填了才会启用 Hub 配置备份。只填一个不生效。 降级行为:未配置时,后端纯本地运行(功能正常),但 restart/stop 后配置会丢失,需重新在后台添加厂商。 付费档用户:
/data已持久,可不配(但配了多一层保险,删 Space 重建也能恢复配置)。
配置方式
在 Space Settings → Variables and secrets:
- Variables:普通环境变量(明文存储,如
PORT、XTC_DB_PATH、HF_CONFIG_REPO) - Secrets:敏感信息(加密存储,推荐用于
XTC_ADMIN_KEY、XTC_ACCESS_KEY、XTC_JWT_SECRET、HF_TOKEN、GEMINI_API_KEY)
五、首次启动验证
1. 等待构建
Space 创建后会自动拉取代码、构建 Docker 镜像。在 Space 主页能看到构建日志,看到 Running on http://0.0.0.0:7860 即构建成功。
2. 健康检查
访问 https://<你的用户名>-xtc-backend.hf.space/health,应返回:
{"ok": true, "service": "xtc-backend-hf", "version": "..."}
3. 登录后台
访问 https://<你的用户名>-xtc-backend.hf.space/admin,输入 XTC_ADMIN_KEY 登录。
4. 添加厂商
在后台 厂商 Tab:
- 点击"添加厂商"
- 填写:
- ID:
gemini(或任意唯一标识) - 名称:
Gemini - 类型:
gemini - API Keys:填入你的 Gemini API Key(每行一个,支持多密钥轮询)
- ID:
- 保存
- 设为默认厂商
5. 测试对话
在后台 测试 Tab,输入消息测试是否正常返回。
6. 测试 API
curl -X POST https://<你的用户名>-xtc-backend.hf.space/v1/chat/completions \
-H "Authorization: Bearer <XTC_ACCESS_KEY>" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-flash-latest",
"messages": [{"role": "user", "content": "你好"}]
}'
六、Cloudflare Workers 反向代理(可选但推荐)
解决三个问题:
- 免费域名:HF Spaces 默认域名
*.hf.space在国内可能无法访问 - 国内访问:CF Workers 节点在国内可达
- 48h 休眠保活:HF 免费档 48h 无请求会休眠,CF Workers 定时器保活
1. 创建 Worker
在 Cloudflare Dashboard → Workers & Pages → Create Worker:
export default {
async fetch(request) {
const url = new URL(request.url);
url.hostname = '<你的用户名>-xtc-backend.hf.space';
return fetch(url, request);
},
// 每 24 小时保活一次
async scheduled(event, env, ctx) {
ctx.waitUntil(fetch('https://<你的用户名>-xtc-backend.hf.space/health'));
}
};
2. 配置定时器
Worker Settings → Triggers → Cron Triggers:
0 */12 * * *
(每 12 小时触发一次,保活)
3. 绑定自定义域名(可选)
Worker → Settings → Triggers → Custom Domains,添加你自己的域名。
七、数据备份与恢复
自动备份(配置文件)
配置了 HF_TOKEN + HF_CONFIG_REPO 后,每次在后台修改厂商配置都会自动把配置 JSON 推送到 HF Hub dataset 仓库的 config/app_config.json。无需手动操作。
手动备份
后台 → 概览 Tab 有"导出配置"按钮,可下载 app_config.json(含所有厂商配置)到本地。
如需备份完整数据库(含会话/日志),需通过 SSH/终端方式(HF Spaces 付费档支持)复制 /data/xtc.db。
恢复
- 免费档 restart/stop 后:
/data被清空,但启动时后端会自动从 Hub 拉取config/app_config.json恢复配置(需已配置HF_TOKEN+HF_CONFIG_REPO)。其余数据(会话/日志)丢失。 - 付费档重建后:
/data保留,所有数据自动恢复,无需操作。 - 删除 Space 重建:先配置环境变量(含
HF_TOKEN+HF_CONFIG_REPO),启动后配置自动从 Hub 恢复;或登录后台 → 厂商 → 导入手动导出的配置 JSON。
八、常见问题
Q1: 重建 Space 后配置丢失?
原因:免费档磁盘是 ephemeral,restart/stop 会清空 /data;且未配置 HF Hub 配置备份。
解决:
- 配置
HF_TOKEN+HF_CONFIG_REPO环境变量(见第三节第 3-4 步),启用配置自动备份 - 启动时后端会自动从 Hub 拉取配置恢复
- 或开通付费持久存储($5/月),
/data永久保留
Q2: 后台登录提示 "invalid admin key"?
原因:XTC_ADMIN_KEY 环境变量未设置或拼写错误。
解决:Space Settings → Variables and secrets 检查 XTC_ADMIN_KEY,注意 Secrets 修改后需要重启 Space。
Q3: 手表端请求返回 401?
原因:XTC_ACCESS_KEY 不匹配,或请求头格式错误。
解决:
- 请求头格式:
Authorization: Bearer <XTC_ACCESS_KEY> - 检查环境变量值是否前后有空格
Q4: Space 休眠了怎么办?
原因:HF 免费档 48h 无请求自动休眠。 解决:
- 配置 Cloudflare Workers 定时器(见第六节)
- 或用外部监控服务(如 UptimeRobot)每 5 分钟 ping
/health
Q5: 怎么查看请求日志?
后台 → 请求历史 Tab,默认保留最近 500 条完整请求(含标头、body、响应、耗时、错误码)。可在该 Tab 调整保留条数(0-2000)。
Q6: 怎么添加多个 API Key 做轮询?
后台 → 厂商 → 编辑厂商 → API Keys 字段,每行填一个 key,自动轮询。
Q7: 国内访问慢/连不上?
- 用 Cloudflare Workers 反向代理(见第六节)
- 或绑定自定义域名走 CF CDN
九、环境变量完整清单
# ===== 必填 =====
XTC_ADMIN_KEY=<你的后台管理密钥>
XTC_ACCESS_KEY=<前端访问密钥>
XTC_JWT_SECRET=<32位以上随机字符串>
# ===== 默认值(通常不用改)=====
PORT=7860
XTC_DB_PATH=/data/xtc.db
XTC_DISABLE_ADMIN=false
UPSTREAM_TIMEOUT_MS=120000
XTC_ACCESS_TOKEN_TTL_SEC=1800
XTC_ACCESS_TOKEN_LENGTH=8
# ===== 种子厂商(可选,留空用后台配)=====
GEMINI_API_KEY=
OPENAI_API_KEY=
OPENAI_BASE_URL=https://api.openai.com
# ===== HF Hub 配置备份(免费档强烈建议)=====
HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxx
HF_CONFIG_REPO=你的用户名/xtc-config
十、文件结构说明
部署后 Space 内的关键文件:
/data/ # 本地存储卷(免费档 ephemeral,付费档持久)
└── xtc.db # SQLite 数据库(所有数据,配置额外备份到 Hub)
/app/ # 应用代码(每次重建从 Git 拉取)
├── Dockerfile
├── requirements.txt
└── app/
├── main.py # FastAPI 入口
├── config.py # 环境变量配置
├── database.py # SQLite 初始化
├── hf_storage.py # HF Hub 配置备份抽象层
├── auth.py # 鉴权(admin key + access key + JWT)
├── middleware.py # 速率限制中间件
├── request_log_middleware.py # 请求日志中间件
├── errors.py # 统一错误模型
├── admin_html.py # 后台 HTML
├── adapters/ # Gemini/OpenAI 适配器
├── services/ # 业务逻辑层(config_store 接入 Hub 备份)
└── api/ # API 路由