逆向 Claude Web 的 MicroVM:揭开 Anthropic 隐藏的 Antspace 平台

HN AI Best Practices 2026-09-11T12:46:33.976132

Claude Code Web 内部是怎样的:一个未剥离符号的 Go 二进制、Anthropic 的机密部署平台,以及一个 AI 原生 PaaS 的架构


起点

我们正在打造 ArcBox,一个从桌面端到平台端的全栈平台,定位类似 Railway 和 E2B。我们的核心理念是本地与云端一致:用完全开源的 ArcBox Desktop 替代 OrbStack,在本地提供沙箱能力。最近我们发现,越来越多的 Coding Agent 平台开始上线网页入口,而且几乎无一例外,底层都选了 Firecracker。Claude Code 也不例外。作为同领域的从业者,我们好奇它的运行环境,于是顺手挖了挖。本来只是随手敲了个 strace -p 1,结果演变成了一场完整的逆向工程,挖出了 Anthropic 尚未发布的基础设施,包括一个完全没有文档的应用托管平台。

本文所有内容,都是在一个 Claude Code 会话里用标准 Linux 工具(strace、strings、objdump、go tool objdump)发现的。没有漏洞利用,没有提权,没有网络攻击。那个二进制就摆在那里,符号没剥,调试信息一应俱全。


第一层:这是个 Firecracker MicroVM

第一个问题:这到底是什么环境?

ACPI 表的 OEM ID 是 FIRECK,创建者 ID 是 FCAT,两者都硬编码在 Firecracker 的源码里。这正是支撑 AWS Lambda 和 Fargate 的那套 MicroVM 技术。

Firecracker MicroVM 架构

配置如下:4 个 vCPU(Intel Xeon Cascade Lake @ 2.80GHz)、16GB 内存、252GB 磁盘、Linux 6.18.5。不支持嵌套虚拟化,因为 Firecracker 会刻意从 guest 中移除 vmx/svm 标志。

进程树精简得离谱:

没有 systemd,没有 sshd,没有 cron,没有日志守护进程。PID 1 是一个自定义二进制文件,同时充当 init 和 WebSocket API 网关。内核命令行证实了这一点:

对 PID 1 执行 strace,可以看到它在跑一个 epoll 事件循环,定期检查 /proc/*/children/proc/*/status 来监控子进程。本质上就是一个极简的 init 监管程序,监听 2024 端口(WebSocket API)和 2025 端口(辅助端点)。


快照架构

会话不是从零启动的——它们是从冻结的虚拟机快照中恢复出来的。dmesg 输出显示,模板创建和会话恢复之间隔了 48.5 小时:

恢复过程中,Firecracker 宿主机热插拔块设备:

initramfs 是刻意精简的:一个 3.1MB 的 cpio 归档,里面只有 /process_api。真正的 Ubuntu 根文件系统在 ext4 块设备(vda)上,恢复时才注入。该 ext4 的挂载计数为 11,说明这个镜像已经被 11 个会话复用过了。

Snapstart:延迟挂载模式

模板创建阶段:

  1. Firecracker 启动:内核 + 3.1MB initramfs

  2. process_api 执行最小初始化:挂载 /proc/sys/dev、cgroups;配置网络(IP=192.0.2.2/24,GW=192.0.2.1,MTU=1400)

  3. 向宿主机发送 SNAPSTART_READY 信号

  4. 宿主机调用 PUT /snapshot/create → 保存整个虚拟机状态

会话恢复阶段:

  1. 宿主机准备会话专属的块设备(vda/vdb/vdc)

  2. 宿主机调用 PUT /snapshot/load,传入新的设备后端

  3. 虚拟机恢复运行——内核检测到设备变化,重新初始化 CRNG

  4. process_api 检测到恢复操作,然后执行:

  5. 丢弃页缓存——残留的模板缓存会返回垃圾数据
  6. 重新挂载 devtmpfs——刷新设备节点
  7. 挂载 ext4 → 通过 pivot_root 切换到新的根文件系统
  8. 挂载 squashfs 覆盖层(claude-code、env-runner)
  9. 通过 clock_settime() 修正墙上时钟——否则会卡在模板的时间点
  10. 丢弃 CAP_SYS_RESOURCE——安全加固
  11. 接受连接——WebSocket 服务器就绪

  12. 丢弃页缓存——残留的模板缓存会返回垃圾数据

  13. 重新挂载 devtmpfs——刷新设备节点

  14. 挂载 ext4 → 通过 pivot_root 切换到新的根文件系统

  15. 挂载 squashfs 覆盖层(claude-code、env-runner)

  16. 通过 clock_settime() 修正墙上时钟——否则会卡在模板的时间点

  17. 丢弃 CAP_SYS_RESOURCE——安全加固

  18. 接受连接——WebSocket 服务器就绪

安全措施


process_api:通信协议

PID 1 对外暴露两个网络接口——一个负责进程管理的 WebSocket API,和一个负责容器控制的 HTTP API。和常见的 init 系统不同,process_api 是一个 Rust/tokio 写的二进制程序,实现了一套完整的远程进程管理能力。

WebSocket API(端口 2024)

连接握手流程:可选的 JWT → ProcessConnectionJSON → 创建进程或重新挂载已有进程。

创建进程时接收一个 CreateProcess 结构体:

I/O 采用两阶段二进制协议:

进程终止的原因包括:正常退出、信号终止、进程级 OOM、容器级 OOM、超时、以及服务器关闭。

在内部,process_api 会为每个进程维护独立的 cgroup(v1 路径在 /sys/fs/cgroup/memory/process_api/,v2 在 /sys/fs/cgroup/process_api/),实现了孤儿进程接管(重新挂到 PID 1 下),并运行一个可配置的 OOM 轮询循环。

HTTP 控制 API(端口 2025)

六个端点用于管理容器生命周期:

/mount_root 端点接收一个 MountRootConfig,里面有网络配置(etc_hosts、resolv_conf)、CA 证书、squashfs 挂载、FUSE 挂载(带 VFS 缓存配置)以及墙上时钟时间戳——从空白快照初始化一个会话所需的全部内容都在这儿了。挂载期间,root 会通过 FIFREEZE/FITHAW 这两个 ioctl 冻结。


第二层:未 strip 的 Go 二进制

真正的发现是 /usr/local/bin/environment-runner(同时被软链接为 environment-manager):

一个 27MB 的 Go 二进制,没有 strip,带着完整的调试信息和符号表。它编译自 Anthropic 的私有 monorepo,路径是 github.com/anthropics/anthropic/api-go/environment-manager/。

用 go tool objdump 和 strings,就能把完整的内部包结构提取出来:

从二进制里提取出的关键依赖:


第三层:Antspace,Anthropic 隐藏的 PaaS

在 tunnel/actions/deploy/ 包里,能看到两个部署客户端的函数符号:

先看预期之中的 VercelClient:

再看意料之外的 AntspaceClient。

从二进制文件中提取相关字符串后,一整套部署协议浮出水面:

阶段一:创建部署

阶段二:上传构建产物

阶段三:流式获取部署状态

在整个公开互联网上搜索"Antspace",一无所获:Anthropic 官网、GitHub、博客、文档、LinkedIn、招聘信息、会议演讲、专利申请——全都查过了,零结果。这个平台从未在任何公开场合被提及。

名字可能来自"Ant"(据说是 Anthropic 员工的内部昵称)加上"Space"(托管空间),跟 Heroku、Vercel 这类平台的命名思路一样。

Antspace vs. Vercel:架构差异

Anthropic 选择从零搭建一套完整的部署协议,而不是简单包装 Vercel 的 API,这说明它是把这件事当战略级平台来做的,不是临时接一下。


第四层:Baku,Web 应用构建器

"Baku"是 claude.ai 上 Web 应用构建功能的内部代号。当你在网页端让 Claude 帮你构建一个 Web 应用时,它会启动一个 Baku 环境。

从二进制文件中提取的内嵌资源来看:

项目模板:

Supabase 自动配置:

六个 MCP 工具开箱即用:

  1. provision_database:按需创建 Supabase 项目
  2. execute_query:执行 SQL 查询
  3. apply_migration:版本化 schema 变更,自动生成类型
  4. list_migrations:列出已应用的迁移
  5. generate_types:根据数据库 schema 重新生成 TypeScript 类型
  6. deploy_function:部署 Supabase Edge Functions

自动写入 .env.local 的环境变量:

Stop Hooks(内嵌 shell 脚本):

Baku 环境带有一个 pre-stop hook(停止前钩子),在以下情况会阻止会话结束:

默认部署目标:Antspace,而不是 Vercel。Vercel 只是备选方案,Baku 的原生部署路径走的是 Anthropic 自家的平台。

内部组织结构:


第 5 层:BYOC(Bring Your Own Cloud,自带云)

envtype 包中包含两套环境的实现:

  1. anthropic:由 Anthropic 托管(基于 Firecracker MicroVM)
  2. byoc:Bring Your Own Cloud,客户自带云

BYOC 让企业客户可以把 environment-runner 跑在自己的基础设施上,而会话仍由 Anthropic 的 API 来编排。关键特性如下:

BYOC 的 API 接口共 7 个:


战略格局

我们眼前的,是一个垂直整合的 AI 应用平台:

这已经不只是 AI 编程助手,而是一个 AI 原生 PaaS 架构——用户从萌生想法到上线生产,整个过程都发生在 Anthropic 自己的基础设施内。

这在竞争层面的影响相当大。Anthropic 由此直接对标:

但它有一项结构性优势,是这些对手都不具备的:Anthropic 掌控着整条技术栈——从理解你意图的大语言模型,到构建代码的运行时,再到托管应用的平台,全在自己手里。


方法

所有发现都是在我自己的 Claude Code 会话里,用标准 Linux 工具拿到的。具体步骤如下:

第 1 步 — 识别 hypervisor。dmesg | grep FIRECK——ACPI 表里带着 OEM ID,一眼就能锁定 Firecracker。

第 2 步 — 识别 PID 1。cat /proc/1/cmdline——可以看到 /process_api 是个自定义 init,而不是 systemd。--firecracker-init 这个参数更坐实了这一点。

第 3 步 — 提取 Go 构建元数据。对 environment-runner 二进制跑 go version -m,能得到 Go 版本、模块路径(github.com/anthropics/anthropic/api-go)、(devel) 单体仓库标记,以及完整的依赖清单。

第 4 步 — 从符号还原包结构。二进制没被 strip(剥离符号),所以 objdump -t 能直接给出带完整包路径的函数名。筛出 environment-manager/internal/ 并提取唯一路径,就能还原出完整的架构树。

第 5 步 — 有针对性的字符串提取。对 Go 二进制直接 strings | grep 噪音很大(链接器会把所有字符串字面量拼在一起)。有两种更靠谱的思路:

第 6 步 — 用符号表反推功能。objdump -t binary | grep 'deploy\.' 能列出每个组件的方法清单——Vercel 和 Antspace 两套客户端连同完整方法签名,就是这么被发现的。

第 7 步 — 运行时观察。strace -p 1 -e trace=epoll_pwait,read,write -f 证实了 epoll 事件循环、子进程监控以及 WebSocket 通信模式。

之所以能这么做,全靠这几点:(1)二进制没被 strip——这是最关键的一条;要是 strip 过,就得上 Ghidra 了。(2)Go 自带的构建元数据等于一份免费的依赖清单。(3)Go 的字符串拼接模型保留了结构体 tag 和错误字符串。(4)VM 里有 root 权限,才能对 PID 1 跑 strace。


写在最后

把一个没做剥离、带着完整调试符号的二进制文件直接发到生产环境……这算是一种「选择」吧。它让这次分析变得毫无难度。通常需要动用 Ghidra、老老实实反编译好几个小时才能搞定的事,用 go tool objdumpgrep 就完事了。

Antspace 显然还处在早期或内部阶段(版本号前缀是 staging-),但部署协议本身已经相当成熟,达到了生产级别。Anthropic 到底打算把它做成公开产品,还是只当 Claude 网页体验背后的内部基础设施,目前还看不出来。

能确定的是,Anthropic 的野心远不止做一家大语言模型和 AI 智能体公司。他们正在为这样一个世界打地基——应用可以被「说」出来就存在,而他们想把这套技术栈的每一层都握在自己手里。

查看原文