前言
最近想搭一个linux虚拟机来玩ai工具,主要是codex cli和gemini cli这些东西。结果整个安装过程磕磕绊绊,最后总算在ai的帮助初步成功了。期间踩了不少坑。写个流水账记录一下吧。
虚拟机安装
本人的宿主机是debian12。由于之前在windows下安装过VMWare workstation。想着这玩意比较有名,而且现在还免费了,所以准备也采用VMWare workstation。下载后安装,结果直接给我来个需要编译内核文件。网上找了一通,发现有人在linux安装也会遇见,主要还是debian的更新策略太保守(这是一个很频繁的坑)。但是研究了下发现解决起来太麻烦,遂放弃。改为让AI给我推荐一下在debian12下安装哪种虚拟机最合适。结果AI大力推荐KVM + virt-manager,这个作为Linux原生方案,最稳定、性能最好(顺便把VMWare给贬低了一通)。所以我最终选择的方案是:Debian 12 安装 KVM + virt-manager。最终方案如下:
1
2
3
4
5
6
7
8
9
|
Debian 12 (host)
└── KVM
└── Ubuntu VM
├── Docker
├── Codex CLI
├── Python
├── Node.js
├── MCP
└── AI tools
|
确认 CPU 支持虚拟化
执行如下命令。如果输出:0。说明:BIOS没开启虚拟化或 CPU 不支持,那就不用往下进行了。如果大于0就没问题。
1
|
egrep -c '(vmx|svm)' /proc/cpuinfo
|
安装KVM全家桶
- 执行如下命令:
1
2
|
sudo apt update
sudo apt install qemu-kvm libvirt-daemon-system virt-manager ovmf dnsmasq-base bridge-utils
|
这里面几个包的作用如下:
| 包 |
作用 |
| qemu-kvm |
虚拟机核心 |
| libvirt-daemon-system |
后台虚拟化服务 |
| virt-manager |
图形化管理器 |
| ovmf |
UEFI 固件 |
| dnsmasq-base |
NAT 网络 |
| bridge-utils |
网桥支持 |
- 启动 libvirt 服务
安装完成后执行如下命令确认服务开启:
1
2
3
|
sudo systemctl enable --now libvirtd
systemctl status libvirtd
active (running) //看到这个证明服务已正常启动。
|
执行:
如果输出如下,说明:libvirt 正常。
1
2
|
|Id | Name | State |
|----|------|---------|
|
- 把当前用户加入 libvirt 组(否则每次都要sudo)
1
2
|
sudo usermod -aG libvirt $USER
reboot
|
下载Ubuntu ISO
目前最新的是26.04版本。建议下载24.04版本的。因为版本太新对后续安装ai cli工具可能会有点影响。另外建议安装Ubuntu Server版本(没有gui)。另外建议把下载后的iso文件放入/var/lib/libvirt/images/文件夹并修正权限:
1
2
|
sudo cp ~/Downloads/ubuntu-24.04*.iso /var/lib/libvirt/images/
sudo chmod 644 /var/lib/libvirt/images/*.iso
|
启动 virt-manager
virt-manager
你会看见GUI界面,这就是以后主要操作入口。注意你此刻应该看见的是qemu:///system,而不应该是qemu:///session。建议通过virt-manager –connect qemu:///system来打开virt manager。
创建第一个 Ubuntu VM
- 在virt-manager中点击:File->New Virtual Machine。
- 选择Local install media。
- 选择镜像文件。直接选择刚刚放入/var/lib/libvirt/images/下面的iso文件。这里注意,取消下方Automatically detect from installation media的勾选。然后在choose operation system you are install下方输入ubuntu22.10或者任意显示的版本。这个不会影响你当前版本的安装。其实直接选Generic Linux也没问题。
- CPU和内存:3c8g。硬盘60G qcow2。
- 勾选Customize configuration before install,然后点击finish。
- 现在会进入虚拟机硬件设置:
- 在overview中把BIOS改成UEFI x86_64(也就是OVMF)
- 在CPUs中选择host-passthrough(虚拟机直接使用宿主 CPU 特性)
- 磁盘改成VirtIO(默认可能是SATA)
- 网卡改成virtio
- 点击Begin Installation开始安装。

- 安装完成后执行如下命令:
1
2
3
4
|
sudo apt update
sudo apt upgrade -y
sudo apt install openssh-server(安装ssh,如果刚才安装镜像时已经选择了,这里可以略过)
ip a(查看vm ip)
|
- 从宿主机SSH登录虚拟机。如果成功登陆,那恭喜你,VM安装就成功了。
推荐安装开发环境
1
2
3
4
5
6
7
8
9
10
11
|
sudo apt install -y \
git \
curl \
wget \
unzip \
zip \
vim \
tmux \
htop \
jq \
build-essential
|
配置Git
1
2
|
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
|
安装Node.js
AI Cli本质上都是Node.js。但是这里不建议直接apt install来安装,因为版本可能会比较老。推荐使用 NVM。
1
2
3
4
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
nvm install --lts
node -v //应该是Node 22.x
npm -v //应该是npm 10.x+
|
安装Python:
1
2
3
|
sudo apt install python3 python3-pip python3-venv -y
python3 --version
pip3 --version
|
安装AI Cli:
1
2
|
npm install -g @openai/codex //codex cli
npm install -g @google/gemini-cli //Gemini Cli
|
安装完成后一些注意事项:
重启宿主机后再启动KVM报错。
安装好ubuntun并且也能ssh进去。但是重启宿主机之后,打开virt-manager后点击run,系统提升如下错误信息: Error starting domain: Requested operation is not valid: network ‘default’ is not active。这个时候运行如下命令:virsh uri。如果显示qemu:///session,那么大概率是重启后virt-manager自动回退到session模式了。这时候只要执行如下指令就能切换会system模式:
1
2
3
4
|
sudo virsh -c qemu:///system net-list --all(表面上查network,实际它隐式激活了system libvirt环境)
Name State Autostart
--------------------------------
default active yes
|
这个操作过一次后后面应该就不会再切换回session模式了。如果要稳妥一点的话,建议每次通过virt-manager –connect qemu:///system来启动virt-manager。再确认 libvirtd 自动启动
1
2
3
|
systemctl is-enabled libvirtd
应该输出:enabled。否则:
sudo systemctl enable --now libvirtd
|
另外执行如下命令开机默认开始虚拟网卡:
1
2
|
sudo virsh net-start default(立即启动 default NAT 网络)
sudo virsh net-autostart default(让它以后开机自动启动)
|
推荐专门建一个共享宿主机目录。以方便在宿主及机和VM之间传递文件。KVM官方推荐共享文件系统virtiofs。
1
2
3
4
5
6
7
8
9
|
Debian(宿主机):/home/john/workspace
│
│ virtiofs
▼
Ubuntu(虚拟机):/mnt/workspace
qemu-system-x86_64 --version //7.x或者8.x都支持virtiofs。
which virtiofsd //确认virtiofsd已安装
sudo apt install virtiofsd //virtiofsd
|
在virt-manager中配置:
- 关闭虚拟机
- 打开:virt-manager,选择你的Ubuntu虚拟机。右键点击:Open -> Show virtual hardware details(那个灯泡图标)。点击:Add Hardware。
- 选择:Filesystem。配置:Driver:virtiofs,Source Path:宿主机目录,Target Path:例如workspace(这里不是路径,只是一个标签名)。如果出现“You may need to ‘Enable shared memory’ on the ‘Memory’ screen.”的提升,需先在Memory里面开启"Enable shared memory"选项。
- 点击:Finish

1
|
sudo apt install -y virtiofsd //实际上客户端内核已经支持。主要确保工具齐全。
|
1
|
sudo mkdir -p /mnt/workspace
|
- 挂载目录。假设刚才Target写的是workspace:
1
|
sudo mount -t virtiofs workspace /mnt/workspace
|
1
|
df -h //应该能看到:workspace或者virtiofs设备。
|
- 设置开机自动挂载(/etc/fstab中增加一行):
1
2
3
4
|
sudo vim /etc/fstab
workspace /mnt/workspace virtiofs defaults 0 0
sudo systemctl daemon-reload
sudo mount -a
|
- 在宿主机和虚拟机两边都执行“id”命令,确保两边的id相同,后续不会有访问权限的问题。
三、创建KVM快照(折腾之前先做一个快照,以后搞坏了可以直接回滚,比重装 Ubuntu 快得多)
- 创建快照
1
2
3
4
5
6
|
virsh domblklist ubuntu22.10
Target Source
-----------------------------------------
vda /var/lib/libvirt/images/ubuntu22.qcow2
如果是:*.qcow2,那快照体验最好。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
打开 virt-manager
↓
选中 ubuntu22.10
↓
Open
↓
Snapshots
↓
Take Snapshot
或者同等功能的命令行:
virsh shutdown ubuntu22.10
virsh snapshot-create-as ubuntu22.10 before-ai-tools "Before installing Gemini CLI and Codex CLI"
virsh snapshot-list ubuntu22.10
Name Creation Time
--------------------------------------------
before-ai-tools 2026-06-05 16:30
|
1
2
3
|
virsh shutdown ubuntu22.10
virsh snapshot-revert ubuntu22.10 before-ai-tools
virsh start ubuntu22.10
|
- 备份整个镜像文件(推荐)
上面创建快照的方法其实就是在KVM中打了个tag。未来可以回滚回这个tag。他并没有真正备份整个KVM镜像文件。如果要备份整个KVM镜像文件:
1
2
3
4
|
virsh shutdown ubuntu22.10
sudo cp /var/lib/libvirt/images/ubuntu22.10.qcow2 /var/lib/libvirt/images/ubuntu22.10-before-ai-tools.qcow2
或者:
sudo qemu-img convert -O qcow2 /var/lib/libvirt/images/ubuntu22.10.qcow2 /var/lib/libvirt/images/ubuntu22.10-before-ai-tools.qcow2
|
这样你得到一个真正独立的磁盘镜像:
1
2
|
ubuntu22.qcow2
ubuntu22-before-ai-tools.qcow2
|
以后需要恢复时:
1
|
sudo cp /var/lib/libvirt/images/ubuntu22.10-before-ai-tools.qcow2 /var/lib/libvirt/images/ubuntu22.10.qcow2
|
注意:当KVM使用pflash固(OVMF/UEFI),libvirt不支持对KVM创建内部快照,只能使用镜像文件备份的方式。
关于KVM的网络(NAT模式下):
- virbr0 可以理解成一个“虚拟交换机 + 虚拟路由器 + NAT网关”的组合体。libvirt默认会创建一个网络。这个default网络对应virbr0。更准确的说法virbr0是libvirt自动创建的一个虚拟NAT网络,其中virbr0本身是虚拟交换机(bridge),而 libvirt + dnsmasq + NAT 规则共同组成了一个“小型虚拟路由器”。
1
2
3
4
5
6
7
|
virsh net-list
Name State
----------------
default active
ip addr show virbr0 //通常显示192.168.122.1/24
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Internet
│
▼
家用路由器:192.168.1.1
│
▼
Debian:192.168.1.100
│
▼
virbr0:192.168.122.1 (KVM的默认网关)
│
▼
Ubuntu VM:192.168.122.100
|
- libvirt自动启动了dnsmasq,专门服务于virbr0网络,用来做dhcp服务。
1
2
3
4
|
sudo iptables -t nat -L
192.168.122.0/24
↓
192.168.1.100
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
Internet
│
▼
家用路由器:192.168.1.1
│
▼
┌────────────────────────┐
│ Debian宿主机 │
│ 192.168.1.100 │
│ │
│ virbr0 │
│ 192.168.122.1 │
└──────────┬─────────────┘
│
┌─────────┴─────────┐
│ │
▼ ▼
Ubuntu VM1 Ubuntu VM2
192.168.122.100 192.168.122.101
|
- KVM会创建一对虚拟网卡。其中一个是KVM中的虚拟网卡,另一个则是虚拟机网卡在宿主机侧的接口(vnet0)。如果把virbr0比作一个交换机,那么vnet0就相当于交换机上的一个网口(另一头连着KVM的虚拟网卡)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
virbr0 ← 虚拟交换机(Bridge)
│
└── vnet0 ← 虚拟机网卡在宿主机侧的接口
virbr0
│
├── vnet0 → Ubuntu
├── vnet1 → Debian测试机
└── vnet2 → Windows VM
Ubuntu VM:192.168.122.100
│
│ (虚拟网卡 ens3)
▼
====================
vnet0
====================
│
▼
virbr0:192.168.122.1
│
▼
NAT
│
▼
Debian宿主机:192.168.1.x
│
▼
家庭路由器
│
▼
Internet
|
KVM配置科学上网
由于搭建KVM的主要目的是要使用AI Cli。所以科学上网这块是必须要配置的。各个AI Cli理论上都是HTTP API/HTTPS请求,所以推荐最简单的方式就是用宿主机科学工具(比如V2rayN)+KVM环境变量代理”。
- 宿主机V2rayN在设置中打开允许局域网连接选项,并且最好打开TUN模式(处理全局不确定流量)。KVM只做环境变量代理(SOCKS/HTTP)。设置成KVM的网关IP,也就是virbr0的IP。
1
2
3
4
5
6
7
8
9
10
|
VM (192.168.122.10)
↓
virbr0 (192.168.122.1) ← VM 的“默认网关”
↓
宿主机 NAT
↓
Internet
virbr0 = 虚拟局域网的“路由器”
192.168.122.1 = 路由器 LAN 口 IP
VM = 连接在这个 LAN 上的电脑
|
- KVM设置如下环境变量(写入~/.bashrc)并验证。这里有个坑要注意下:每次在KVM创建新用户后,不要忘了把下面的环境变量加入~/.bashrc中。不然AI Cli会连接不上。
1
2
3
|
export ALL_PROXY=socks5h://192.168.122.1:10808
export all_proxy=socks5h://192.168.122.1:10808
curl --proxy socks5h://192.168.122.1:10808 https://ipinfo.io
|
Codex Cli登录
-
Codex登录失败错误
首先检查:
1
|
curl -i https://auth.openai.com/api/accounts/deviceauth/usercode
|
如果看到:
1
2
3
4
5
|
{
"error": {
"code": "unsupported_country_region_territory"
}
}
|
基本就可以直接判断是网络出口问题。一般是~/.bashrc中没有设置代理环境变量。
-
登录成功后出现bubblewrap警告
如果Codex登录后出现“Codex could not find bubblewrap on PATH. Install bubblewrap with your OS package manager.”,说明bubblewrap没有安装。bubblewrap(简称 bwrap)是 Linux 上的轻量级沙箱工具。Codex 在执行代码时会用它创建隔离环境,例如:
1
2
3
4
5
6
7
8
9
|
Agent
↓
Codex Sandbox
↓
Shell
↓
Python
↓
Git
|
安装bubblewrap:
1
2
3
4
|
sudo apt update
sudo apt install uidmap bubblewrap
echo "kernel.apparmor_restrict_unprivileged_userns=0" | sudo tee /etc/sysctl.d/99-codex-userns.conf
sudo sysctl --system
|
KVM常用命令