# Azure VM 自托管 E2B：架构、协议、认证、业务流程

本文聚焦 E2B Runtime。当前 Device 项目运行于独立 Device VM，旧 E2B 主机的网页入口只做重定向；物理部署与逻辑端侧不能混用。[四方案交互架构、定位、性能与成本模型](./architecture.html#comparison)同时覆盖 Foundry Hosted Agent、Dynamic Sessions 和尚未部署的 ACA Sandboxes 设计，并区分官方能力与实测边界。

这里部署 E2B 官方开源 Runtime，不是 SaaS 代理或自制兼容 API。使用 Azure Embed Terraform 模块、Compose、API、Orchestrator、envd、client-proxy、原生 Dashboard。上游固定提交 `78d5ff91515b58a9bd2d0b28b14f80428c63d15e`，Apache-2.0。

## 部署架构

```mermaid
flowchart LR
  Device["线下浏览器 Agent\nlocalStorage / IndexedDB"] -->|HTTPS 7444 / Bearer| Gateway["Azure VM / Caddy TLS"]
  Gateway --> Controller["业务控制平面 / Session"]
  Gateway --> Dashboard["上游 E2B Dashboard"]
  Controller -->|loopback 3000 / Team Key| API["上游 E2B API"]
  API --> Orchestrator["上游 Orchestrator"]
  Orchestrator --> KVM["Firecracker / KVM microVM"]
  Controller -->|官方 SDK / Connect RPC| Proxy["client-proxy / envd"]
  Proxy --> KVM
  Controller -->|HTTPS / Managed Identity| Blob["Azure Blob agent-demo"]
```

线下 Agent 是浏览器中的规则式调度与本地工具，不模拟完整手机，不冒充大模型。提醒完全本地；文件和文档任务依据 Query 及文件自主委派云端。

云端是一台 Ubuntu 24.04、Intel D8s_v5 / 32 GiB Azure VM，位于容量为 1 的 Flexible VMSS。Firecracker 使用 `/dev/kvm` 和 `/dev/net/tun`，真实运行 microVM。Docker 仅承载控制服务，不替代 microVM 隔离。

Terraform 创建独立 RG、VNet、NSG、客户端与 NAT 静态 IP、NAT Gateway、托管身份、私有 Blob 容器、角色授权、DNS、TLS 入口及应用扩展。原始 HTTP、DB、Orchestrator 控制端口不向公网开放。

当前使用经确认的 `runtime.stat200.net`；Device 位于独立的 `device.stat200.net`。独立 DNS root 管理现有 Azure DNS zone 的选定 A 记录，Caddy 向公开 CA 申请并校验真实证书，不回退到自签名或关闭 TLS 校验。私有 Terraform `public_domain` 支持自有 hostname；公共 IP 派生域名只作为旧配置兼容，不用于规避组织访问策略。

## 通信与端口

| 端口 | 协议 / 用途 | 认证与限制 |
|---|---|---|
| 443 | HTTPS / Device 页面与文档 | 页面公开，业务调用另需访问码 |
| 7444 | HTTPS / JSON / multipart / 业务 API | 设备或管理员 Bearer |
| 7443 | HTTPS / 官方 E2B API | X-API-Key，操作员 CIDR |
| 8443 | HTTPS / envd Connect RPC | SDK 逐沙箱访问令牌，操作员 CIDR |
| 9443 | HTTPS / 上游原生 Dashboard | Team Key、Secure Cookie、操作员 CIDR |
| 80 | HTTP / ACME 校验及 HTTPS 跳转 | 不提供明文业务 API |
| 3000–3002 | 宿主 loopback HTTP | 宿主 INPUT 防火墙拒绝所有非 loopback 访问 |

外部 SDK 必须同时设置 Terraform 输出的 `E2B_API_URL`、`E2B_SANDBOX_URL`、`E2B_API_KEY` 和模板 `base`。Controller 同机时使用 loopback。配置缺失就报错，不回退到 E2B SaaS。

进程和文件调用由官方 SDK 封装 Connect RPC，不是自制 REST。base 不承诺 Jupyter；自托管路径用 `commands.run("python3 ...")` 执行真实文件，而不是调用不存在的 Code Interpreter 服务。

8443 的 Caddy 入口将上游 Host 规范为 `127.0.0.1:3002`，保留 SDK 的 `E2b-Sandbox-Id`、`E2b-Sandbox-Port` 和访问令牌。上游 client-proxy 只对 IP/localhost 或 `sandbox.` 共享域名启用头部路由，普通自定义域名原样传入会返回 `Invalid host`；这一步只修正路由，不取消鉴权。

## 认证与信任边界

1. Device：`POST /api/login`，设备访问码换取设备绑定、24 小时有效的 HMAC-SHA256 签名 Bearer。它不是 JWT。
2. Session 绑定 device_id；其他设备无法读取会话或文件。管理员使用独立访问码；设备不能提升角色。
3. E2B Team Key 由 Terraform 生成并种入此部署数据库，仅 Controller 与操作员持有，不下发 Device。
4. envd：SDK 使用逐沙箱令牌。微虚拟机只收到文档和可信工具，不收到应用访问码、模型 Key 或 Azure 凭据。
5. 原生 Dashboard 的 Team Key 不等于应用管理员访问码；操作员自行输入，Key 不放 URL；TLS 下 Cookie 标记 Secure。
6. Azure Blob：托管身份在 agent-demo 容器范围写入会话和文件，网络走私有终结点与私有 DNS；不使用 SAS/账户密钥，不允许匿名 Blob。应用 bootstrap 由 Azure VM 扩展受保护设置下发。
7. Terraform state、私有 ZIP 与 `.deployment/vm-access.json` 都含秘密，不得提交或公开 `terraform output -json`。

上游单机模块将秘密写入 VMSS custom data，资源组 Reader 可能读取；不是生产 Key Vault 方案。生产需要 Entra 身份、密钥托管、审计、配额、队列与多节点。

## 业务与调用流程

```mermaid
sequenceDiagram
  participant D as Device Agent
  participant L as 本地工具 / IndexedDB
  participant C as Controller
  participant E as 自托管 E2B API
  participant V as Firecracker / envd
  participant B as Azure Blob
  D->>D: Observe / Plan，按 Query 与文件分流
  alt 提醒
    D->>L: reminders.create → 读取验证
  else 文档
    D->>C: POST Session（Bearer + multipart）
    C-->>D: 202 / 业务 Session ID
    C->>E: Sandbox.create(base)，Team Key
    E->>V: KVM 创建 microVM
    E-->>C: 真实 Sandbox ID
    D->>C: 轮询 handoff → cloud
    C->>V: 官方 SDK：安装、上传、解析、导出
    V-->>C: 文件与结果
    C->>B: 保存结果、事件、SHA-256
    C->>E: Kill
    C-->>D: returning / device
    D->>C: 下载 artifact
    D->>L: SHA-256 校验、文件与便签保存
    D->>C: ACK
    C-->>D: completed
  end
```

状态机 `queued → creating → running → returning → completed`。创建显示 handoff，执行显示 cloud，返回显示 device。失败、取消、中断是显式状态。手机确认本地保存之前不能标记完成；刷新中途可接回结果，重复刷新不重复保存。

每个任务新建独立沙箱，结果写入 Blob 后回收。端侧对话、便签和文件有状态，沙箱任务状态不保留。

## API 契约

| 方法 / 路径 | 结果 / 错误 |
|---|---|
| POST /api/login | token；401 访问码错误，429 限流 |
| GET /api/config、/api/architecture | 模式、部署、硬件证据、协议与流程；401 未登录 |
| POST /api/sessions | query、skill_id、output_format、context、file → 202；413/422/503 明确失败 |
| GET /api/sessions/{id} | 位置、Sandbox ID、事件与结果；404 不存在或无权限 |
| GET /api/sessions/{id}/artifact | 原始字节与 MIME；409 未生成 |
| POST /api/sessions/{id}/ack | 手机确认 → completed；403/409 角色或状态不允许 |
| POST /api/sessions/{id}/cancel | 终止运行任务；409 执行已结束 |
| POST /api/admin/sessions/{id}/timeout | 30–600 秒；403/409 |
| GET /api/admin/runtime | 官方 SDK 读取真实沙箱列表；502 连接失败，不返回模拟列表 |

Device 可视化面板从当前 Controller 读取真实部署和 KVM 实测结果，展示实际 HTTP 方法、路径、状态码与遮蔽的 Bearer 标识；不记录密钥或文件正文。

## 一键部署与真实验收

项目根目录运行 `python3 scripts/deploy_vm.py`。需要 Azure Owner 或 Contributor + User Access Administrator、Azure CLI 登录、Terraform ≥1.7.5、Python 3。命令配置 subscription / CIDR，执行 init、validate、apply，写入私有输出，等待 HTTPS。

`terraform_data` 打包两个独立项目，当前唯一 VM 的 Custom Script Extension 通过受保护设置接收包。原始上游 Compose 使用 gzip/base64 cloud-init 下发，避免本机访问私有 Blob 的循环依赖；改动见 vendored 源码的 PROVENANCE。扩展直接由 Terraform 管理，不混用 VMSS 内联扩展，不需要 SSH；宿主执行 KVM API 12 ioctl、等待上游 base Ready、运行上游真实 sandbox smoke，配置原生 Dashboard HTTPS 与 Caddy。自动替换 VM 在本 Demo 中关闭，宿主替换需显式重新 apply。

依赖已安装时，可运行 `.venv/bin/python scripts/deploy_vm.py --test` 一次完成部署与真实 API / Device 浏览器测试。普通部署也会在 VM 上运行上游 smoke，不只检查 HTTP 存活。

真实验收必须创建非 sim- 的 Sandbox，实际执行 Python、文件读写，Device 自动委派并接回结果，管理界面看到真实 ID，最后 Kill 后没有活动 Sandbox。模拟测试不能替代。

## 业务范围、成本与运行边界

支持文字 TXT/Markdown/CSV/JSON/Word/Excel/PPT/PDF，单文件 5 MB、正文 60,000 字符；导出 Word/Excel/PPT/TXT/Markdown/CSV。音视频/OCR/版式保真不在本轮范围。未配置模型时只有明确标识的摘录/模板/字面替换；真实翻译另需模型，与沙箱真伪是不同边界。

VM、Premium SSD、NAT、公共 IP、Storage 持续计费。单节点不高可用，运行任务遇宿主替换会中断。Blob 会话可保留；上游本地模板重建 base；手机已保存状态不受影响。生产需队列、多节点、备份、留存/删除策略。
