Files
dsh_shenxian/dsh-server-docs/DEPLOY-本部署.md
T
admin 971ccc3703 feat(auth): 注册页人机验证 + 邮箱验证码;品牌标识去 DeepSeek(附域名迁移线 序㊿ 补提交)
三条线合并入库 —— 均已完成并上线(源码与生产一致,此前只部署未入仓)。
⚠️ 其中域名迁移线为**另一会话**产出,本会话只做入库、**未复验其正确性**(它自报零回归)。

【档案 134 · 注册页人机验证 + 邮箱验证码】
- DB 迁移 v10:users.email(唯一索引 LOWER(email))+ email_codes 事件表(2 索引)
- 新增模块 src/web/{register-guard,mail,turnstile,email-code}.ts
- routes/auth.ts:新增 GET /api/auth/register/config、POST /api/auth/register/email-code;
  注册接口加人机验证与验证码校验;config.ts 新增 12 项配置(默认空 ⇒ 不配 = 老行为)
- 邮件走**可插拔驱动**(brevo/http/log),发件人 [email protected](Brevo 域名已认证 + DKIM + SPF)
- 防爆破:三层配额(邮箱 6/h、8/天;IP 20/h;全局 200/h)+ 递增冷却阶梯
  (60→60→180→300→900→1800s)+ 试错 5 次作废 + 码只存哈希 + 单次使用 + 与用户名绑定
- Turnstile 服务端校 **success + action + hostname 三项**:sitekey 是公开的,
  只校 success 时"拿我们的 sitekey 在自己站点替真人取合法 token 再打我们接口"这条路是通的
- 新增 test/register-guard.test.mjs(19 用例)

【档案 137 · 品牌标识改造 — 去 DeepSeek 图形】
- login/register/admin 页头:删 DeepSeek 鲸鱼图标 + 「DeepSeek」文字图形
  → 平台标识(中文「能力枢纽」/英语及其他语言「CapabilityNet」,走 i18n 词条 brand.name)
- portal 顶栏换图标(页面名「管理门户」保留)
- 新建 web/favicon.svg(平台自有 hub 图标,避开 DeepSeek 蓝)+ 四页 favicon 指向它
- 新增 test/i18n-brand.test.mjs(node:vm 跑真实 i18n.js,六条语言路径断言渲染结果)
- scripts/verify-static.mjs 新增 SVG 段:XML 注释不得含 ASCII 双连字符(否则整份 SVG
  解析失败、图标静默不显示 —— 实际踩到过)
- 🔴 会话页面(实例内官方 dsh 界面)的标识**按用户要求未动**(也受 R2 约束)

【档案 135/136 · 域名迁移线(另一会话产出)】
- 域名收敛为 ai1net.com;旧域 alotbuy.com 降级为 301 过渡装置
- src/net/relay/{addr-override,directory,rendezvous,switcher}.ts 种子与候选链更新;
  src/web/server.ts、src/worker/relay-tunnel.ts、scripts/verify-cluster-domain.mjs
- 档案 136 = 控制面按两台中继取并集(**已立项、未落地**)

验证(本会话两条线):新增单测 21 条全通过|全量 221 pass / 0 fail / 1 skipped|
verify-static 全合格|其余 10 个 verify 脚本全 OK|线上实测:Turnstile 假 token 403、
发码 delivered、四页 deepseek 命中 0、favicon 200。
2026-09-19 09:11:24 +08:00

102 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DEPLOY — 本部署说明(ai1net.com / 47.77.182.89)
> 用途:把"这套平台到底部署在哪、装了什么、改了什么、怎么重建/回滚"一次讲清,供后来人(或未来的我)在**不翻聊天记录**的前提下独立重建。
> 对应档案 19 §C9。最后更新:2026-09-19(域名迁至 ai1net.com)
## 1. 拓扑与入口
| 项 | 值 |
|---|---|
| 服务器 | `47.77.182.89`(Alibaba Cloud Linux 8,阿里云)|SSH 别名 `bt-server`(端口 32022,root) |
| 门户 / 用户实例 | **`https://ai1net.com`** / **`https://<用户名>.ai1net.com`**(Cloudflare 代理,回源走 443) |
| 旧域名 | `alotbuy.com`(含 `*.alotbuy.com`、`*.dsh.alotbuy.com`)→ **301** 到新域(2026-09-19 降为过渡装置;`relay-direct.alotbuy.com` 与 `/dshs-relay`、`/dshs-overlay/bootstrap` 仍透传) |
| 面板 | 宝塔(站点 vhost 由面板管理,注意:面板保存会**重写** vhost,可能抹掉自定义指令) |
| 编排器 | 自研 `dshs`(Node/TS),systemd 单元 `dshs`,监听 `127.0.0.1:3080` |
| 被托管运行时 | 官方 **`@deepseek-ai/[email protected]`**(全局安装于 `/usr/local/lib/node_modules/@deepseek-ai/dsh`,**平台不改其任何文件**) |
## 2. 目录布局
| 路径 | 说明 |
|---|---|
| `/opt/dshs` | 编排器**源码仓库**(也是 git 仓库;`lib/` 被 .gitignore 忽略 → 需构建) |
| `/var/lib/dshs` | dataRoot:`dshs.db`(better-sqlite3)、`users/<uuid>/` |
| `<userRoot> = dataRoot/users/<uuid>` | 每用户根:`ws/`(工作区,用户可见)、`home/`(DSH_HOME:profiles/sessions/storages/skills)、`tmp/`(1777) |
| `<profile> = <userRoot>/home/profiles/web` | 该用户的 dsh profile:`node_modules/`、`cordis.patch.yml`、`package.json`、`pnpm-lock.yaml` |
| `/opt/dsh/` | 运维脚本与备份:`switch-domain-alotbuy.sh`、`backups/`、`artifacts/`(插件 tgz) |
| `/www/server/panel/vhost/nginx/` | `ai1net.com.conf`(**现役门户**)、`relay-direct.conf`(443/TCP 兜底)、`alotbuy.com.conf`(**2026-09-19 降级为 301**)、`dsh.alotbuy.com.conf`(301)+ 多份 `.bak-*` |
| `/etc/letsencrypt/live/{ai1net.com,alotbuy.com,dsh.alotbuy.com}/` | 证书(新域 DNS-01 via `/etc/cloudflare-ai1net.ini`;旧域 via `/etc/cloudflare.ini`) |
## 3. 环境变量(`/etc/dshs.env`)
| 键 | 作用 |
|---|---|
| `DSHS_PORT` | 编排器监听端口(127.0.0.1:3080) |
| `DSHS_DATA_ROOT` | dataRoot |
| `DSHS_BASE_DOMAIN` | 门户/用户子域基域(现 `ai1net.com`) |
| `DSHS_COOKIE_DOMAIN` | 会话 Cookie 域(现 `.ai1net.com`;见档案 22 §五 取舍说明) |
| `DSHS_SECURE_COOKIES` | Cookie `Secure` 标记(HTTPS 下应开) |
| `DSHS_DSH_BIN` | 子实例可执行路径 |
| `DSHS_ISOLATION_MODE` | 隔离模式(本部署 `account` = bwrap + setpriv + systemd-run scope) |
| `DSHS_BASE_UID` | 每用户 uid 起始值 |
> 其余可调项走代码默认值(崩溃退避/熔断、idle-reap、bundled skill dir 等),见 `src/config.ts` 的 `DEFAULT_*` 与档案 20。
## 4. 外部依赖(版本为实测)
| 依赖 | 版本 | 用途 |
|---|---|---|
| Node | **22.23.2** | 编排器与子实例运行时 |
| pnpm | **9.15.9** | profile 侧插件安装账本(`pnpm-lock.yaml`) |
| bubblewrap | **0.4.0** | 每用户沙箱(合成根 + 只读系统 + 私有 tmp + `--unshare-pid`) |
| systemd-run | — | per-instance scope(**MemoryHigh=448M(基础/软限) + MemoryMax=1024M(上界/硬限)**,**与插件开关无关**(档案 **96**)/ CPUQuota=150% / TasksMax=128) |
| nginx | 1.28.3(宝塔) | 站点与反代(关键自定义指令见档案 21/22) |
| nftables | — | 出网护栏(`/etc/nftables-dsh-egress.nft` + `dsh-egress.service`) |
| sqlite3 CLI | 3.26 | 仅运维排查(平台内置用 better-sqlite3) |
| certbot + dns-cloudflare | — | 证书签发/续期(**必须** `--dns-cloudflare-propagation-seconds 60`,否则失败) |
## 5. 平台侧脚本族
| 脚本 | 作用 |
|---|---|
| `ensure-role-profile-patch.cjs` | 角色化 profile patch(非 admin 隐藏模型分区/收归插件开关) |
| `ensure-workspace-picker.cjs` | 目录选择器收敛**全量/新用户铺开**(写平台段 + 逐用户 pnpm add;幂等,`--dry-run/--restart`) |
| `scripts/install-workspace-picker.sh <tgz>` | 逐用户安装插件包(自动判断是否加 `pnpm -w`) |
| `/opt/dsh/switch-domain-alotbuy.sh` | 域名切换(改 env → drain → 重启) |
| `/usr/local/bin/provision-new-users.sh` | 新用户供应(建 OS 账号 + chown + **调用 picker 铺开**);由 `dsh-provision.path` 触发 |
| `scripts/ci.sh` | 类型检查 + 构建 + 单测(不含需要实例/凭据的 smoke) |
## 6. 构建 / 部署 / 回滚(三步)
```bash
# 构建(改代码后必做;lib/ 不入库)
cd /opt/dshs && npm run build && bash scripts/ci.sh
# 部署(drain: 停服务 → 清残留实例 → 起服务)
systemctl stop dshs; for p in $(ps -eo pid,user,args | awk '$2 ~ /^dsh-/ {print $1}'); do kill $p; done; systemctl start dshs
# 回滚(示例:回滚到某个提交)
git -C /opt/dshs revert <sha> && npm run build && systemctl restart dshs
```
- **本机 ↔ 服务器同步**:服务器无 Gitea 凭据 → 服务器 `git bundle create` → 本机 `git fetch <bundle>`(**路径必须用 `D:/…`**)→ `merge --ff-only` → `push`。
- **文档库**:`bash scripts/docs-sync-check.sh`(双端 md5 对账,0 = 全绿);服务器侧 `/opt/dsh/docs`(root 600)。
## 6.5 定时维护(cron,2026-09-11 建立)
| 任务 | 文件 | 时间 |
|---|---|---|
| 存储用量快照 | `/etc/cron.d/dsh-maintenance` | 每小时 :05 |
| 工作区清理 / 会话回收 / 回收站清空 | 同上 | 04:10 / 04:20 / 04:40 |
| **平台全量备份 + 旧备份清理** | `/etc/cron.d/dsh-backup` | 每周日 05:00 / 05:30 |
> 备份脚本 `/opt/dsh/backup.sh`(入库副本 `scripts/backup-platform.sh`)含 SQLite 一致性快照;恢复步骤见档案 02 附录 C.8。
## 7. 默认红线(改任何东西前先读)
1. **不自动升级 dsh**;升级必须走"测试 → 评估 → 修复",并按档案 26 回归清单逐项验。
2. **不改官方 dsh 主程序与缓存**(`/usr/local/lib/node_modules/@deepseek-ai/dsh/**` 保持原封)。
3. client bundle **禁 `exports.default`**(R3)。
4. 未明确要求**不擅自 commit/push**(服务器 git 与文档 git 都一样)。
5. 服务器 `/opt/dsh/docs` 保持 root 600。
> 相关档案:01(架构)|02(运维,含附录 C 速查)|21(nginx 性能/流式)|22(域名迁移)|26(升级耦合点与回归清单)