VPS 可以執行 Proxmox 嗎?巢狀虛擬化檢查
多數 VPS 供應商會隱藏 vmx 旗標。使用 kvm-ok 在 1 分鐘內檢查,了解能否執行 KVM 或 Proxmox guest,以及會看到的確切錯誤訊息。
簡短答案
巢狀虛擬化是指在虛擬機器內執行 hypervisor:您的 VPS 已經是 guest,而您希望它再託管自己的 guest。只有在供應商的 hypervisor 明確將 CPU 的虛擬化擴充功能公開給您的執行個體時,這項功能才會運作。請檢查 /proc/cpuinfo 是否有 vmx 旗標(Intel)或 svm 旗標(AMD);如果兩者都沒有,您在 VPS 內進行的任何設定都無法修正這個問題。
先釐清一點:Docker 不需要這些功能。 容器共用 VPS 的 kernel,且完全不會使用 /dev/kvm。如果實際需求是「在我的伺服器上於容器中執行數個服務」,您目前已有所需條件。需要巢狀虛擬化的情況,包括使用 第二個 kernel、建立 Proxmox 實驗環境、執行 Windows guest、使用 Firecracker microVM、執行 Android emulator、建立由實際 VM 組成的 Kubernetes 測試環境,或執行會啟動 VM 映像檔的 CI runner。
實際上嵌套了哪些內容
共有 3 層:
- L0,實體機上的供應商 hypervisor。您無法存取這一層。
- L1,您的 VPS。對 L0 而言,這只是一個 guest。
- L2,您想在 VPS 內執行的 VM。
硬體虛擬化在 Intel 上是 VT-x(vmx flag)搭配 EPT,在 AMD 上則是 AMD-V / SVM(svm)搭配 RVI/NPT。hypervisor 使用這些指令進入 guest mode,讓 CPU 同時走訪兩層 page table。
這些機制原本都不是為了重入而設計,因此嵌套必須透過模擬完成:當 L1 執行 VMLAUNCH 或 VMRESUME 等 VMX 指令時,會 trap 到 L0。L0 會代替 L1 維護 L2 的 shadow structure。在支援 VMCS shadowing 的 CPU 上,L1 的 VMREAD 與 VMWRITE 可以在不觸發 exit 的情況下處理。這能減少大量相關流量,但無法消除其他額外處理。KVM 在這方面的效率不錯,但每次 exit 仍由 L0 額外處理,因此供應商必須明確啟用這項功能。
當 L0 使用 KVM 時,加速 L2 必須同時符合以下 2 個條件:
- L0 的 KVM module 必須以
nested=1載入。 - L0 必須提供帶有該 flag 的 CPU model 給您的 VPS:在 libvirt 中為
<cpu mode='host-passthrough'/>,在 Proxmox 中為cpu: host,在 raw QEMU 中為-cpu host。通用的 emulated model(qemu64、kvm64)會隱藏vmx,即使全域已啟用 nesting 也一樣。
其他 hypervisor 也有各自的開關。例如 Hyper-V 會在其 VM 內,為 nested hypervisor 模擬虛擬化擴充功能,但只有逐一啟用 nesting 的 VM 才能使用。
在 1 分鐘內檢查 VPS
# 1. Are you in a VM, and under what?
systemd-detect-virt # kvm, vmware, xen, microsoft, or "none" on metal
# 2. Does the CPU expose the extensions to you?
grep -o -E 'vmx|svm' /proc/cpuinfo | sort -u
lscpu | grep -i -E 'virtual|hypervisor'
# 3. The definitive check
sudo apt update && sudo apt install -y cpu-checker
kvm-ok
# 4. The device node the whole stack depends on
ls -l /dev/kvm可用的執行個體會顯示 vmx 或 svm,kvm-ok 的內容為 KVM acceleration can be used,而 /dev/kvm 會以 root:kvm 模式 660 存在。如果旗標存在,但裝置節點不存在,請手動載入模組,並查看 kernel log:
sudo modprobe kvm_intel # or kvm_amd
sudo dmesg | tail -n 20有一個檔案經常被引用,也經常遭到誤解:
cat /sys/module/kvm_intel/parameters/nested # Y or N在 VPS 內,這是 你的 KVM 模組設定,控制 L2 guest 是否能再巢狀執行第三層 guest。它不表示 L0 是否已為你啟用巢狀功能;/proc/cpuinfo 和 kvm-ok 才能回答這個問題。nested 參數是在你完全擁有的機器上設定的控制項:
echo 'options kvm_intel nested=1' | sudo tee /etc/modprobe.d/kvm-nested.conf
sudo modprobe -r kvm_intel && sudo modprobe kvm_intelVM 執行期間不允許移除模組,因此請先關閉所有 guest。若該機器是 Proxmox host,在 Proxmox VE 9 啟用巢狀虛擬化 會說明相同的 modprobe.d 變更,以及讓該旗標在 guest 內可見的每個 VM cpu: host 設定。
為什麼多數 VPS 主機商會關閉此功能
- 即時遷移。 提供
vmx代表必須公開包含該旗標的 CPU 型號;而依賴這些 CPU 功能的 guest,無法安全遷移到 CPU 不支援這些功能的機器。主機商若透過遷移客戶工作負載來清空節點,啟用巢狀虛擬化後就會失去這項彈性。 - 攻擊面。 巢狀 VMX/SVM 路徑屬於 kernel 虛擬化層中最複雜的程式碼之一,也有相應的 CVE 歷史。
- L0 不一定是 KVM。 如果
systemd-detect-virt顯示vmware、xen或microsoft,巢狀虛擬化規則就由該堆疊決定,而不是由 KVM 決定。
執行個體沒有該旗標嗎?請洽詢支援人員(部分主機商可針對個別 VM 啟用),選擇明確記載支援巢狀虛擬化的方案,或改用 dedicated box。以下內容假設您在顯示該旗標的機器上擁有 root 權限。
使用 libvirt 執行 L2 guest
sudo apt install -y qemu-system-x86 libvirt-daemon-system virtinst ovmf
sudo systemctl enable --now libvirtd
sudo usermod -aG libvirt,kvm "$USER" # log out and back in
virt-install \
--name guest1 \
--memory 2048 \
--vcpus 2 \
--cpu host-passthrough \
--disk path=/var/lib/libvirt/images/guest1.qcow2,size=20,format=qcow2,bus=virtio \
--network network=default,model=virtio \
--os-variant debian13 \
--location https://deb.debian.org/debian/dists/trixie/main/installer-amd64/ \
--graphics none \
--console pty,target_type=serial \
--extra-args 'console=ttyS0,115200n8'不需要圖形工作階段。序列埠安裝需要一段時間,因此請在持久化 shell 中啟動;相同的 在 VPS 上維持 Claude Code 工作階段的 tmux 工作流程,可讓 virt-install 主控台在 SSH 連線中斷後仍保持連線。若 --os-variant debian13遭拒,表示您的 osinfo-db早於該版本,請執行 osinfo-query os,並選擇一個已存在的名稱。--cpu host-passthrough會將 vmx向下轉送至 L2,只有在 L2 也必須執行虛擬化時才需要。使用 virsh autostart guest1讓 guest 能安全啟動。
磁碟與 NIC 上的 virtio匯流排並非裝飾:模擬的 IDE 與 e1000 裝置比 virtio 佇列更常陷入 hypervisor,而在巢狀虛擬化中,L0 無法自行完成的 exit 會向上反映至 L1;L1 處理該 exit 時,可能進一步觸發自身的 exit。
網路:教學通常略過的部分
您的 VPS 只有一個公用 IP,且位於會過濾未知 MAC 位址的網路架構後方。因此會產生兩個結果。
將 L2 guest 橋接到公用網路通常無法運作。 將 br0 設定在公用 NIC 上,並為 guest 指定自己的 MAC 位址。您會看到 ARP 封包送出,卻沒有任何回應,因為供應商的交換器會丟棄來自未租用給您的 MAC 位址之框架。如果出現這種現象,請停止除錯 bridge;這就是實際機制。
請改用 NAT 網路。 libvirt 會提供 default:virbr0、192.168.122.0/24、dnsmasq 租約,且可立即使用對外連線。若要處理連入流量,請在 L1 終止 TLS,再將流量代理進來。以下憑證路徑來自 使用 Certbot 在 Nginx 上申請 Let’s Encrypt 憑證:
server {
listen 443 ssl;
server_name lab.example.com;
ssl_certificate /etc/letsencrypt/live/lab.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/lab.example.com/privkey.pem;
location / {
proxy_pass http://192.168.122.50:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}請先為 guest 設定靜態租約(virsh net-edit default),讓 proxy_pass 中的位址固定不變。
管理介面不應暴露在網際網路上:5900 上的 VNC 與 8006 上的 Proxmox Web UI 應繫結至 loopback,透過 SSH tunnel(ssh -N -L 8006:127.0.0.1:8006 you@your-vps)存取,或經由 在 VPS 中自架 WireGuard VPN 連線。如此一來,整個 192.168.122.0/24 guest 範圍只需經過一個私有網路躍點即可到達。防火牆規則請維持精簡,只允許 sudo ufw allow 22,80,443/tcp,其他一律拒絕。若啟用 ufw 後 guest 立即失去對外連線,通常是因為 DEFAULT_FORWARD_POLICY="DROP" 位於 /etc/default/ufw。請將其設為 ACCEPT,再重新載入 ufw。
VPS 上的 Proxmox
Proxmox VE 9 底層使用 Debian 13,因此可在 Debian VPS 上加入 pve-no-subscription repository 並安裝 proxmox-ve package。請從 Proxmox 官方目前的文件取得 repository 與 keyring 設定行。從舊部落格文章複製的 URL 可能會導致安裝失敗。在開始處理下方的網路設定前,應先確認 Proxmox 是否適合部署在租用硬體上。家用 Proxmox 主機與租用 VPS 的成本及能力比較已先完成電力與硬體的計算,可直接用來評估這個問題。
套件不是最困難的部分。Proxmox 預期 vmbr0 會橋接至實體 NIC,但這會直接遇到前述的 MAC filtering dead end。在 VPS 上可行的架構,是使用沒有連接實體埠的 NAT'd 或 routed vmbr0,讓 guest 位於 private range,並在 host 上設定 DNAT rules 或 reverse proxy,處理需要公開存取的服務。若對外服務是 container 而非 VM,使用 Traefik 從單一 Docker Compose 檔案代理多個 app可執行相同的 routing 工作,並自動管理憑證。先建立 Snapshot /etc/network/interfaces:錯誤的 bridge 定義可能會讓你無法連回沒有 console 存取權的機器。
誠實說明效能
巢狀虛擬化比單層虛擬化慢,而且原因很明確,不是廣泛分散的額外負擔:成本主要發生在離開 guest mode 和位址轉譯,而不是一般指令。 存在 EPT/NPT 時,L0 會將 L1 為 L2 建立的頁表與自身頁表合併到同一個 shadow table,因此 TLB 命中時可達到硬體原生速度。TLB 未命中時成本較高:硬體會同時走訪 guest 的頁表與 shadow table,而 L1 對自身頁表所做的每次變更,都會觸發 exit,讓 L0 重新同步 shadow table。成本較高的是所有會離開 guest mode 的操作,包括 I/O、計時器中斷、MMIO 及處理器間中斷,因為 L2 exit 由 L0 處理,且可能再經由 L1 反映回去。以小型工作集執行 CPU-bound 工作時,效能接近原生;大型記憶體內工作集會承擔 TLB 未命中的成本,而以 syscall、封包及磁碟 I/O 為主的工作則會明顯受到這些層次影響。
因此,所有地方都使用 virtio 裝置。此外,你的 qcow2 檔案位於供應商已經虛擬化的磁碟上,形成兩層疊加的 thin provisioning;此時 guest 磁碟上的 cache=none 會使相同區塊同時存在於兩個 page cache 中。這裡不提供基準測試數據,請在自己的 instance 上測量自己的工作負載。
失效模式與您會看到的字串
INFO: /dev/kvm does not exist / KVM acceleration can NOT be used 來自 kvm-ok。模組可能尚未載入,或旗標未公開。先檢查 /proc/cpuinfo。
kvm: disabled by bios 出現在 dmesg 中。在實體機器上,請在韌體中啟用 VT-x/SVM 選項。在 VPS 中,這表示 L0 未將這些擴充功能交給您;您在 guest 中輸入任何指令都無法改變此狀況。
modprobe: ERROR: could not insert 'kvm_intel': Operation not supported。 kernel 所看到的 CPU 沒有 vmx。這同樣是 L0 的決定。
Could not access KVM kernel module: Permission denied。 問題在權限,不是硬體。ls -l /dev/kvm 應顯示群組 kvm 與模式 660;請將自己加入該群組,並啟動新的登入 shell,因為群組成員資格不會套用到已執行中的工作階段。
QEMU 啟動時出現 kvm: Device or resource busy。另一個 hypervisor 模組已佔用 CPU:執行 lsmod,尋找 vboxdrv 或 VMware 模組,以及 kvm_intel;然後卸載不需要的模組。
從 virsh 傳回 /var/run/libvirt/libvirt-sock: No such file or directory。daemon 已停止:sudo systemctl enable --now libvirtd。
Proxmox:KVM virtualisation configured, but not available. guest 在無法提供 KVM 加速的 host 上啟用了 KVM 加速。請修正巢狀虛擬化設定,或取消勾選並接受模擬執行。
Android emulator:x86_64 emulation currently requires hardware acceleration! 再次檢查 /dev/kvm,通常是群組權限問題。
完全沒有錯誤,但所有作業都極其緩慢。 未指定 accelerator flag 的 QEMU 會退回使用 TCG,也就是軟體模擬器。這種方式可正常運作,但速度很慢;原本以秒計的開機時間會變成以分鐘計。請明確傳入 -accel kvm,讓 QEMU 在發生問題時停止並顯示錯誤,而不是靜默進行模擬。
guest 在執行期間消失。 請在 dmesg 中尋找 Out of memory: Killed process ... qemu-system-x86_64。L2 guest 是 L1 上的程序,OOM killer 會以一般程序的方式處理它。L2 的 RAM 取自 L1 的固定配置,無法向 host 借用記憶體。
操作方式:備份、升級與限制
備份。 複製執行中 guest 的 qcow2 映像可能產生不一致的映像,因為 guest 在讀取期間仍會持續寫入。請執行 virsh shutdown guest1,等待 virsh domstate guest1 回報 shut off 後再進行複製(關機命令返回時,guest 可能仍在停止);或建立外部快照(virsh snapshot-create-as guest1 snap1 --disk-only --atomic),讓寫入內容改存至 overlay,同時複製目前靜態的基礎映像,之後再使用 virsh blockcommit guest1 vda --active --pivot 將變更合併回去。請將複本移出 VPS;儲存在同一磁碟上的快照無法防範磁碟故障。
升級。 apt full-upgrade 會安裝新的 kvm_intel/kvm_amd 模組,但執行中的 kernel 會繼續使用舊模組,直到重新開機。請保留上一個 kernel,並在每次變更 kernel 後重新執行 kvm-ok:如果主機重新啟動後缺少 vmx,只要選擇另一個開機項目即可恢復運作。
擴充限制。 只有一個公開 IP 時,所有 L2 服務都必須透過 L1 上的代理或 DNAT 規則連到外部網路。無法進行即時遷移。CPU 發生爭用時,巢狀虛擬化的退出路徑會最先受到影響。此外,具備多個 guest 的 hypervisor 本身已經用掉主機的 RAM;巢狀 VM 無法透過 overcommit 解決固定的資源配置。當實驗環境超出這些限制時,解決方案不是再增加一層巢狀架構,而是改用專用主機,讓你成為 L0,且不再受上述限制影響。
FAQ
執行 Docker on a VPS 需要 nested virtualization 嗎?
不需要。容器會共用 VPS 的 kernel,且不會開啟 /dev/kvm,因此沒有 vmx 或 svm flag 的一般 instance 也能正常執行 Docker 和 Docker Compose。只有在需要第二個 kernel 時才與 nesting 有關,例如 Proxmox lab、Windows guest、Firecracker microVM、Android emulator,或會啟動 VM image 的 CI runner。
如何確認 VPS 是否支援 nested virtualization?
執行 grep -o -E 'vmx|svm' /proc/cpuinfo | sort -u,接著從 cpu-checker package 執行 kvm-ok。可用的 instance 會輸出 vmx(Intel)或 svm(AMD),kvm-ok 會回報 KVM acceleration can be used,而 /dev/kvm 應存在,且 group 為 kvm、mode 為 660。此問題可忽略 /sys/module/kvm_intel/parameters/nested;該檔案描述的是你自己的 KVM module,不是 provider 的 hypervisor 對你公開的功能。
為什麼大多數 VPS provider 會停用 nested virtualization?
公開 vmx 代表要提供帶有該 flag 的 CPU model。依賴這些 CPU feature 的 guest 無法 live migrate 到 CPU 不具備這些 feature 的 machine,因此會在節點之間搬移客戶的 provider 通常會停用此功能。Nested VMX/SVM code path 也有很長的 CVE 歷史。部分 host 仍可依每個 VM 的需求開啟此功能,另一些則將 nesting 列為方案功能。
我的 nested VM 在 public bridge 上沒有網路。問題在哪裡?
Provider 的 switch 會丟棄來自未租用給你的 MAC address 的 frame,因此橋接到 public NIC 的 L2 guest 送出 ARP 後不會收到回應。不要再針對 br0 進行除錯,改用 libvirt 的 NAT default network(virbr0、192.168.122.0/24),為 guest 指定 static lease,再透過 VPS 本身的 reverse proxy 或 DNAT rule 公開服務。
Nested VM 會慢多少?
效能成本主要出現在 VM exit 和 address translation。啟用 EPT/NPT 時,L2 內部的 instruction 與 TLB hit 會以硬體速度執行,但 TLB miss 需要走訪額外的 page table;I/O、timer interrupt、MMIO 和 IPI 則由 L0 處理,可能還要經過 L1 返回。CPU-bound 工作若 working set 較小,效能會接近原生;大型 in-memory working set,以及大量使用 syscall、packet 或 disk 的工作負載,則會明顯受到每一層的影響。所有位置都使用 virtio device,並在 guest disk 上啟用 cache=none,再測量你自己的工作負載。