- scripts/host-init.sh: 幂等宿主初始化(btrfs pool + project + profile + UFW/iptables 修复) - images/base/build.sh: Debian13 base 镜像构建脚本 - .memory/project.md: 设计决策、坑点、进度记录 状态: Phase 1 完成, Phase 2 base 镜像构建被 SSH 断开中断, sb-builder 已 stop 保留,续跑需改 systemd-run 抗 SSH 断开。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.6 KiB
5.6 KiB
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-<userId> 容器 × N(默认 stopped,调用时起)
↓ exportFile
MinIO(192.168.2.221:9000)
生命周期
| 阶段 | 触发 | 动作 |
|---|---|---|
| 创建 | better-auth user.create | incus copy lobe-sandbox-base → sb-<userId>,不启动 |
| 激活 | 首次 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 <<EOF &跑后台任务,SSH 断开时脚本跟着死。应改systemd-run --unit=xxx或setsid真正脱离 shell
- ⏸ Phase 3 Orchestrator 服务(Bun HTTP,15 工具)
- ⏸ Phase 4 LobeChat 侧接入(4 文件小改)
- ⏸ Phase 5 存量补建 + 联调 + 上线
关键路径速查
本地
- 项目根:
/Users/kangwan/Projects/business/20260418-lobe-sandbox-backend/ - 宿主初始化脚本:
scripts/host-init.sh - base 镜像构建脚本:
images/base/build.sh
VPS(2.24.28.41)
- 构建日志:
/var/log/build-sandbox-base.log(第一次,卡 UFW) - 续跑日志:
/var/log/build-sandbox-base.log.2(第二次,SSH 断开死) - 构建脚本副本:
/root/build-sandbox-base.sh - Incus 数据:
/var/lib/incus/ - btrfs pool 文件:
/var/lib/incus/disks/lobe-sandbox-pool.img(200GiB 稀疏)
Incus 操作(切到 lobe-sandbox project)
incus list --project lobe-sandbox
incus profile show sandbox-default --project lobe-sandbox
incus image list --project lobe-sandbox
规划中的 / 待决
- PyPI 本地缓存镜像(nginx 反代清华源)—— 让
uv pip install秒级 - npm 本地缓存(Verdaccio)
- exportFile 对接 MinIO 的 presigned URL 上传流
- 用户删除的手动清理脚本 + 定时 GC(better-auth 没有 user.delete hook)