AI agent 很强大,也很好玩,但安全风险不容忽视。尽管它们普遍提供了一定的 sandbox 机制,直接在宿主机上运行 claude code、codex、openclaw 的风险依然很大,严重时甚至可能导致数据泄露或经济损失。因此,我只在虚拟机中使用 AI agent。
给 AI agent 使用的虚拟机,最好做到「即用即抛」:即使被 AI 折腾坏了,也能直接丢弃重建。为此,可以先制作一台模板虚拟机;以后需要新实例时,直接从模板克隆,即可实现开箱即用。在我的电脑上,30-40s 可得到一台全新、开箱即用的虚拟机实例。
模板虚拟机 aiboxtmpl
我们先制作模板虚拟机 aiboxtmpl,新的虚拟机实例将由它克隆得到。aiboxtmpl 需要充分考虑常见使用场景,提前做好软件安装和系统配置,从而使得运行全新虚拟机的成本降到最低。
虚拟机是用 VirtualBox 管理的。基本配置:
- 2 CPU、2GB 内存,128GB 虚拟硬盘。
- OS: Ubuntu Server
- 网卡:需要 3 块,分别为 NAT、Bridge、Host-only。
网络配置
Ubuntu Server 需要设置 3 个网卡,类型与用途为:
- NAT。默认路由,目的是使虚拟机借用宿主机的翻墙能力。走 dhcp。
- Bridge。使虚拟机在局域网也拥有单独 IP,和局域网里其他机器一样。也走 dhcp 获取 IP。目的是方便与他人协作,比如暴露开发中的服务给其他人使用;如果只用 NAT,则需要手动设置端口转发,不方便。
- Host-only。需要先在 VirtualBox 设置一个 Host-only 网络。此网卡设置固定 IP,便于宿主机通过固定 IP 访问虚拟机,比如 ssh 登录,及访问开发中的服务。
我们在 VirtualBox 上为虚拟机设置的网卡 1,2,3,在 Ubuntu 中网卡名字通常会对应为 enp0s3、enp0s8、enp0s9(具体需以 ip addr 的实际结果为准)。
在 /etc/netplan/50-cloud-init.yaml 里进行网卡设置。
内容如下:
network:
version: 2
ethernets:
# NAT 网络(用于访问互联网)
enp0s3:
dhcp4: true
# Bridge 网络(局域网访问)
enp0s8:
dhcp4: true
# 避免 bridge 网络抢默认路由
dhcp4-overrides:
use-routes: false
# Host-only 网络(固定 IP),用于宿主机 SSH 登录
enp0s9:
dhcp4: false
addresses:
- 10.77.0.102/24
这里关键是,要根据网卡的类型来决定如何配置,而不只是看网卡的名字。可用 ip addr 命令查看各网卡 IP,用 ip route 命令查看路由。
软件包安装
先更新系统到最新状态,然后安装基础软件包。
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential pkg-config cmake libssl-dev libsqlite3-dev
sudo apt install -y tree zip
安装 GitHub CLI gh
命令见文档,看起来很复杂,主要的逻辑是添加 GitHub CLI 的官方 APT 软件源,然后通过 apt 安装。
有了 gh,AI agent 可以执行与 GitHub 代码仓库有关的操作,比如查看 issue,发 PR,review 等等。
安装 Node.js
通过 NodeSource 提供的 APT 软件源安装,见 Node.js Distributions。 选择好版本后,复制对应命令并执行即可。
安装 codex CLI
官方给出的安装方式是通过 npm:
npm i -g @openai/codex
事实上,查看 codex 代码 会发现,codex 现在几乎完全由 Rust 实现。其 js 代码,仅仅是检查所处平台,以确定对应的 Rust 编译出的二进制文件,然后启动子进程而已。
不过,在虚拟机上编译 codex Rust 代码非常耗资源耗时,没什么必要。通过 npm 下载安装预编译好的 Rust 二进制程序,方便快捷。
安装 Rust 及生态工具
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup component add rustfmt clippy rust-src rust-analyzer
# rg, fd, tokei, dust, mdbook
cargo install ripgrep fd-find tokei du-dust mdbook
安装 Python 生态工具
Ubuntu 系统自带了 Python,这里主要是安装 uv,并用 uv 安装 Python 生态工具。
uv 的安装方式有许多,建议用 Standalone Installer 安装。通过这种方式安装的,可通过 uv self update 更新。
# Standalone installer 方式安装
# 安装到 ~/.local/bin 目录,有两个二进制文件,uv, uvx
curl -LsSf https://astral.sh/uv/install.sh | sh
# 设置 bash 自动补全
echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc
有了 uv,就不需要 pipx 了。暂时只安装 ipython。
# 会安装两个可执行文件 ipython, ipython3
uv tool install ipython
安装 playwright
playwright 支持多种语言,如 Node.js 和 Python 等等,但 playwright 是用 Typescript 开发的,其他语言只是 binding。这里用 uv 安装 Python 版。
uv tool install playwright
# 安装 Playwright 所需浏览器 Chromium、Firefox、WebKit
playwright install
# 需要安装一些系统依赖,浏览器才能正常运行。
playwright install-deps
需要注意的是,playwright CLI 不支持 headless 模式,这意味着在 Ubuntu Server 上我们无法用 playwright 命令行操作浏览器。以下命令会报错:
$ playwright open --headless https://www.baidu.com
error: unknown option '--headless'
(注意,playwright 库仍然是支持 headless 模式的,只是需要通过代码来控制。)
但是,安装 playwright 命令行,下载浏览器,及安装依赖,提前搞定这些非常必要。当 AI agent 写代码通过 playwright 操作浏览器时,可以减少因浏览器或系统依赖缺失而产生的报错。
配置 shell 及 vim
将 rc.sh 文件复制到 ~,并在 .bashrc 末尾加一行:
. "$HOME/rc.sh"
另,将 .vimrc 复制到 ~,然后打开 vim,就会自动安装各种插件了。以 yegappan/lsp、preservim/nerdtree、ctrlpvim/ctrlp.vim 等插件为核心,再配合各种快捷键设置,在 rust-analyzer 的加持之下,我用 vim 写 Rust 代码的体验,已经接近 IDE 了。
清理系统
安装完成后,清理系统,减少虚拟磁盘占用的空间。
# dd 命令持续将 0 写入到 /EMPTY,直到写满磁盘。
# 退出时会报错,这是预期行为,不必担心:
# dd: error writing '/EMPTY': No space left on device
sudo dd if=/dev/zero of=/EMPTY bs=1M
# 写满后删除 /EMPTY
sudo rm -f /EMPTY
关闭虚拟机后,用 VirtualBox 的命令行工具 VBoxManage 压缩虚拟磁盘文件。
# aiboxtmpl.vdi 是虚拟磁盘文件
VBoxManage modifymedium disk aiboxtmpl.vdi --compact
在我的电脑上,aiboxtmpl.vdi 占用的空间,从 12GB 压缩到了 8.6GB,效果明显。而另一台用了很久的虚拟机,同样操作之后,占用的磁盘空间从 64GB 下降到 24GB。
使用方式,及注意事项
aiboxtmpl 仅作为模板,应保持干净;不应包含任何 API key,不应登录 GitHub 或者 codex,也不应 clone 任何代码仓库。
当我们需要一台 aibox 时,只需从 aiboxtmpl 复制出一个新的虚拟机即可。在我的电脑上,复制一台虚拟机需要的时间在 30-40s。半分钟即可得到一个开箱可用的全新虚拟机,非常令人满意了。
使用过程中如果发现缺少一些工具,直接在复制得到的 aibox 实例上安装。如果工具比较通用,则同时在 aiboxtmpl 上安装。
如果同时有多台 aibox 虚拟机同时运行,它们的 Host-only 网卡 IP 会冲突。需要在 /etc/netplan/50-cloud-init.yaml 文件修改 IP。
需要特别说明的是,以上这套做法主要是为了降低 AI agent 对宿主机的直接影响,并提升系统损坏后的恢复速度。它并不意味着虚拟机本身就是完整的安全边界;API key 权限、代码仓库权限、共享目录、浏览器登录态、桥接网络暴露面等问题,仍需单独控制。
其他方案
市面上已经有一些现成的工具,可以实现这篇文章的需求,比如 multipass 和 Vagrant。
几年前我使用过一段时间 multipass,但它在 macOS 上可靠性不太好,经常报错,这几年就没再使用了。
Vagrant 也可以完成此文提到的全部操作。将 aiboxtmpl 制作为 Vagrant Box,然后在 Vagrantfile 里定制化虚拟机实例即可。但我对 Vagrant 使用不多,也缺乏了解,所以就没考虑了。如果你熟悉 Vagrant,它也许会是更合适的方案。