Files
dsh_ai1net_server/dsh-server-docs/DEPLOY-本部署.md
T
admin e6207aa691
build / build-and-scan (push) Canceled after 0s
chore(仓库对齐): 文档库结构治理 + IM/插件线落地
文档库:目录改为编号制(01-规范/02-架构设计/03-数据库/04-调整方案/
05-交接单/06-ops/07-scripts/08-skills/09-archive),顶层散文件归入 01-规范/;
INDEX.md 与 docs-manifest.json 重刷(档案 146 篇);旧目录名引用全量对齐。

IM 线:src/im/**(SDK / hub / store / presence / ws / gateway-token)、
src/web/routes/im.ts、src/db/plugin-data/**、src/supervisor/plugin-assembly.ts
及对应 test/**。

插件线:poc/{im-agent-bridge,im-connection-gateway,im-conversation-tabs,
business-plugins-im,carbon-mcp-probe}、src/web/routes/{sessions,overlay-device}.ts、
src/net/relay/{device-grant,instance-credential}.ts。

仓库卫生:清出 40 个历史误入库 / 已改名文件(34 个交接单归档 + 6 个旧结构,
本地均有副本);dsh-server-docs/.gitignore 补 tmp/;交接单不入库(政策)。
2026-09-24 07:25:16 +08:00

123 lines
8.1 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`) |
| `07-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` 触发 |
| `07-scripts/ci.sh` | 类型检查 + 构建 + 单测(不含需要实例/凭据的 smoke) |
## 6. 构建 / 部署 / 回滚(三步)
```bash
# 构建(改代码后必做;lib/ 不入库)
cd /opt/dshs && npm run build && bash 07-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 07-scripts/docs-sync-check.sh`(双端 md5 对账,0 = 全绿);服务器侧 `/opt/dsh/docs`(root 600)。
## 6.4 数据库初始化(PostgreSQL 13 / 47 本机进程)
DB 不在容器里,是 **47 上本机进程**(`127.0.0.1:15432`)。重建时按序跑:
```sql
-- ① 建角色 + 库(初始形态)
CREATE ROLE dshs LOGIN PASSWORD '<见 config/platform.env>';
CREATE DATABASE dshs OWNER dshs ENCODING 'UTF8' TEMPLATE template0;
-- ② 🔴 插件建库权限(2026-09-23 · B 档拍板)
-- 用途 = 平台侧为每个业务插件建独立库 `dshs_pl_<pluginId>`(一插件一库)
-- ⛔ 只给这一位;⛔ 不得顺手给 CREATEROLE / SUPERUSER
ALTER ROLE dshs CREATEDB;
```
- 连接串只从 systemd drop-in `dshs.service.d/cluster.conf` 取(`DSHS_DB_URL`);⚠️ `source /etc/dshs.env` 会拿到错的 `5432`(见 `CODEBUDDY.md §8`)。
- 回滚②:`ALTER ROLE dshs NOCREATEDB;` ⇒ **已建的 `dshs_pl_*` 库不受影响**,仅新插件建不了库(平台建库口返回 `PG_CREATEDB_MISSING` / 503)。
- ⚠️ 权限校验判据(重建后必跑):`rolsuper=false` · `rolcreatedb=true` · `rolcreaterole=false` —— 多点一位即为权限失控。
- ⚠️ PG **没有**"只允许 `dshs_pl_*` 前缀"的原生机制(实测建任意名库成功)⇒ 库名白名单**只靠平台代码**兜(点生成 + 正则复校 + 建库落台账)。详见 `03-数据库/DB-03-插件数据面规范.md §六`。
- 迁移表由平台启动时 `runPgMigrations` 自动落(v15 起含台账表 `plugin_datastores` / `plugin_data_audit`)⇒ 部署新版本代码后随 `systemctl restart dshs` 自动补齐,⛔ 不需手工建表。
## 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`(入库副本 `07-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(升级耦合点与回归清单)