diff --git a/.memory/project.md b/.memory/project.md new file mode 100644 index 0000000..160b69a --- /dev/null +++ b/.memory/project.md @@ -0,0 +1,122 @@ +# Lobe Sandbox Backend — 自托管沙箱后端 + +## What + +替换 LobeChat 对 `market.lobehub.com` 云沙箱的依赖,改为公司 VPS(2.24.28.41)本地自托管的 **per-user Incus LXC** 工作区。 + +- **服务对象**:`ai.milejoy.com`(公司主)+ `lobehub.kang-kang.com`(个人备份,同 backend) +- **隔离粒度**:每个 LobeChat 用户一个 Incus 容器,跨对话共享文件系统(概念对标 ChatGPT Code Interpreter) +- **挂钩点**:better-auth `databaseHooks.user.create.after`(在 LobeChat 项目里改) + +## Why 这个设计 + +- 三条路(a 自建 / b 走 LobeHub 白名单付费 / c 让员工个人账号 OAuth 授权),**a 省钱 + 数据不出公司 + 掌控力** +- 沙箱技术选 Incus LXC(不是 Docker / Firecracker / Daytona): 长命工作区 = 系统容器,公司已有 Incus 栈(hermes-box 同宿主),无新技术栈,CoW 省磁盘 +- btrfs 存储驱动(不是 ZFS):Debian 13 内核原生支持,`apt install btrfs-progs` 零重启,CoW 效果等价 + +## 架构 + +``` +LobeChat (Coolify) + ↓ HTTP 内网(X-Sandbox-Secret HMAC) +Sandbox Orchestrator(Bun 写的 HTTP 服务,systemd 跑在 VPS 宿主机) + ↓ incus CLI(unix socket) +Incus 宿主(VPS 2.24.28.41) + ├── lobe-sandbox project + ├── lobe-sandbox-pool(btrfs 200GiB,CoW) + ├── sandbox-default profile(2GB RAM / 2 CPU / 10GiB disk) + └── sb- 容器 × N(默认 stopped,调用时起) + ↓ exportFile +MinIO(192.168.2.221:9000) +``` + +## 生命周期 + +| 阶段 | 触发 | 动作 | +|---|---|---| +| 创建 | better-auth user.create | `incus copy lobe-sandbox-base → sb-`,不启动 | +| 激活 | 首次 tool 调用 | `incus start` 2-3 秒内可用 | +| 空闲 | 30min 无调用 | `incus stop`,rootfs 保留 | +| 删除 | 手动 / admin | 备份到 MinIO + `incus delete` | + +## 部署目标 + +- VPS: `root@2.24.28.41` +- Orchestrator 端口: `127.0.0.1:8700`(内网,不对外暴露) +- Base 镜像: `lobe-sandbox-base`(Debian 13 + Python 3.13 + Node 20 + Bun + uv + 中文字体) +- Orchestrator 部署路径: `/opt/lobe-sandbox/orchestrator`(TBD) +- systemd unit: `sandbox-orchestrator.service` + +## 关键决策 & 坑点 + +### 1. 存储池用 btrfs 不是 ZFS +原方案 ZFS,实发现 ZFS 在这台 Ubuntu 要 DKMS 编译,可能触发重启(用户规则:不频繁重启服务)。改用 btrfs,内核原生,一键 `apt install btrfs-progs` 零重启,CoW 效果一样。 + +### 2. ⚠️ UFW 挡了 incusbr0 的 DHCP/DNS(大坑) +**现象**:新容器用 `DHCP=true`,`DHCPDISCOVER` 发出去但 `No DHCPOFFERS received`,只拿到 IPv6 SLAAC。 + +**原因**:这台 VPS `iptables INPUT 策略=DROP`(UFW 默认)+ Docker 的 FORWARD chain。默认没放行 incusbr0 的 udp/67、udp/53、tcp/53,也没放 FORWARD。nftables 里 Incus 自己加的规则不生效(iptables 和 nft 都跑,都要通过)。 + +**绕开**:hermes-box 用**静态 IP**(`Address=10.146.223.10/24`),所以没触发这问题。 + +**修复**(已落盘到 `/etc/iptables/rules.v4`,通过 netfilter-persistent 持久): +``` +iptables -I INPUT -i incusbr0 -p udp --dport 67 -j ACCEPT +iptables -I INPUT -i incusbr0 -p udp --dport 53 -j ACCEPT +iptables -I INPUT -i incusbr0 -p tcp --dport 53 -j ACCEPT +iptables -I FORWARD -i incusbr0 -j ACCEPT +iptables -I FORWARD -o incusbr0 -j ACCEPT +``` + +修复后 DHCP 立即可用(容器拿到 `10.146.223.248`)。本地 `scripts/host-init.sh` 里写了这段幂等实现,新环境部署自动修。 + +### 3. Python 版本 +Debian 13 默认 Python 3.13(不是计划的 3.12)。不影响功能,更新。 + +### 4. 沙箱是 per-user 不是 per-topic +对话跨 topic 共享工作区,对齐 ChatGPT Code Interpreter 的心智模型。 + +### 5. 基座"什么都不装"原则 +- 只装必需的运行时(Python/Node/Bun/uv)+ 系统工具(git/curl/build-essential/中文字体) +- **不预装** pandas/numpy/torch/playwright/ffmpeg/libreoffice +- LLM 按需 `uv pip install xxx` — 后续加本地 PyPI 缓存镜像让它快到秒级(尚未做,列在 TODO) + +## 进度(2026-04-18) + +- ✅ Phase 0 Pre-flight(VPS 摸底:31GB RAM / 387GB 磁盘 / Incus 6.0.0 / hermes-box 已跑) +- ✅ Phase 1 宿主初始化(btrfs pool + project + profile + **UFW iptables 修复并持久化**) +- 🔄 **Phase 2 base 镜像构建**(apt 完成,Node 20 安装中/卡) + - 已装:python3.13, build-essential, git, curl, ripgrep, fd, bat, 中文字体, tzdata, locale + - 已装:nodejs 20.20.2(via NodeSource) + - **待装**:corepack + uv + bun + sandbox 用户 + /workspace + publish + - **已踩的坑**:用 `nohup bash -s <