اجرای Proxmox روی VPS با Nested Virtualization
آیا امکان نصب Proxmox روی VPS وجود دارد؟ با دستور kvm-ok قابلیت Nested Virtualization را چک کنید تا از بروز خطاهای CPU در اجرای ماشینهای مجازی مطمئن شوید.
پاسخ کوتاه
مجازیسازی تودرتو (Nested virtualization) یعنی اجرای یک hypervisor در داخل یک ماشین مجازی: VPS شما در حال حاضر یک مهمان (guest) است و شما میخواهید آن را به میزبان مهمانهای خود تبدیل کنید. این قابلیت تنها زمانی کار میکند که hypervisorِ ارائهدهنده شما، تعمیقهای مجازیسازی CPU را به صورت آگاهانه در اختیار instance شما قرار دهد — برای بررسی پرچم vmx (Intel) یا svm (AMD)، بخش /proc/cpuinfo را چک کنید؛ اگر هیچکدام از این موارد ظاهر نشد، هیچ تنظیماتی در داخل VPS مشکل را حل نخواهد کرد.
یک نکته مهم: Docker به هیچکدام از این موارد نیاز ندارد. کانتینرها از kernelِ VPS شما استفاده میکنند و هرگز با /dev/kvm درگیر نمیشوند. اگر هدف اصلی شما «اجرای چندین سرویس در کانتینرها روی سرور» است، شما در حال حاضر تمام موارد مورد نیاز را در اختیار دارید. مجازیسازی تودرتو زمانی اهمیت دارد که به یک kernel دوم نیاز داشته باشید — مانند آزمایشگاه Proxmox، یک مهمان Windows، microVMهای Firecracker، شبیهساز Android، محیط تست Kubernetes با ماشینهای مجازی واقعی، یا runnerهای CI که imageهای VM را بوت میکنند.
آنچه در واقع در حال تودرتو شدن است
سه لایه:
- L0 — هایپروایزر (hypervisor) ارائهدهنده، روی سختافزار اصلی. شما به آن دسترسی ندارید.
- L1 — VPS شما. برای L0، این فقط یک مهمان (guest) است.
- L2 — ماشین مجازی (VM) که میخواهید درون VPS خود اجرا کنید.
مجازیسازی سختافزاری شامل VT-x (پرچم vmx) به همراه EPT در Intel، و AMD-V / SVM (svm) به همراه RVI/NPT در AMD است. یک هایپروایزر از این دستورالعملها برای ورود به حالت مهمان (guest mode) و اجازه دادن به CPU برای پیمایش همزمان دو جدول صفحه (page table) استفاده میکند.
هیچکدام از اینها برای حالت بازگشتی (re-entrant) طراحی نشدهاند، بنابراین تودرتو کردن (nesting) به صورت شبیهسازی شده انجام میشود: وقتی L1 یک دستور VMX را اجرا میکند، به L0 منتقل (trap) میشود و L0 ساختارهای سایه (shadow structures) را برای L2 از طرف L1 مدیریت میکند. KVM این کار را به خوبی انجام میدهد، اما L0 در هر خروج (exit) باید کارهای اضافی انجام دهد — به همین دلیل است که ارائهدهنده باید این قابلیت را فعال کند.
برای داشتن یک L2 با شتابدهنده (accelerated)، هر دو شرط زیر باید برقرار باشند:
- ماژول KVM در L0 با پرچم
nested=1بارگذاری شده باشد. - L0 مدل CPU ای به VPS شما اختصاص دهد که دارای این پرچم باشد — در libvirt عبارت
<cpu mode='host-passthrough'/>، در Proxmox عبارتcpu: host، و در QEMU خام عبارت-cpu hostاست. یک مدل شبیهسازی شده عمومی (qemu64,kvm64) باعث مخفی شدنvmxمیشود، حتی اگر nesting در سطح سراسری روشن باشد.
بررسی 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یک instance قابل استفاده، vmx یا svm را چاپ میکند، kvm-ok مقدار KVM acceleration can be used را نشان میدهد، و /dev/kvm به صورت root:kvm در حالت 660 وجود دارد. اگر flag وجود دارد اما device node موجود نیست، ماژول را به صورت دستی load کنید و 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 شما است و تعیین میکند که آیا یک guest از نوع L2 میتواند nesting سطح سوم را انجام دهد یا خیر. این فایل در مورد اینکه آیا L0 قابلیت nesting را برای شما فعال کرده است یا خیر، چیزی نمیگوید؛ /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_intelحذف ماژول در حالی که یک VM در حال اجرا است امکانپذیر نیست، بنابراین ابتدا guestها را shut down کنید.
چرا اکثر میزبانهای VPS این قابلیت را خاموش نگه میدارند
- Live migration. ارائه
vmxباعث میشود مدل CPU که دارای این flag است نمایش داده شود؛ در این صورت، یک ماشین مهمان که به آن ویژگیهای CPU وابسته است، نمیتواند با امنیت کامل به سیستمی که فاقد آن ویژگیهاست، migrate شود. میزبانهایی که با migration مشتریان، منابع nodeها را آزاد میکنند، به محض فعال کردن nesting، این قابلیت را از دست میدهند. - Attack surface. مسیرهای nested VMX/SVM از پیچیدهترین کدهای لایه مجازیسازی kernel هستند و سوابق CVE متعددی دارند.
- L0 may not be KVM. اگر
systemd-detect-virtخروجیهایvmware،xenیاmicrosoftرا چاپ کند، قوانین nesting مربوط به آن stack است، نه KVM.
اگر در instance خود flagی مشاهده نمیکنید، از پشتیبانی سوال کنید (برخی آن را برای هر VM فعال میکنند)، طرحی را انتخاب کنید که nesting را مستند کرده باشد، یا به یک dedicated box مهاجرت کنید. ادامه این متن با فرض داشتن دسترسی root در سیستمی است که flag را نشان میدهد.
اجرای یک guest از نوع L2 با استفاده از libvirt
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'نیازی به session گرافیکی نیست. فرآیند نصب از طریق serial مدتی طول میکشد، بنابراین آن را در یک shell دائمی اجرا کنید: همان workflow tmux که sessionهای Claude Code را در یک VPS زنده نگه میدارد، یک console از نوع virt-install را در صورت قطع شدن اتصال SSH متصل نگه میدارد. اگر --os-variant debian13 رد شد، یعنی osinfo-db شما قدیمیتر از نسخه منتشر شده است؛ osinfo-query os را اجرا کنید و نامی را انتخاب کنید که وجود دارد. --cpu host-passthrough، مسیر vmx را به داخل L2 فوروارد میکند؛ این کار تنها در صورتی لازم است که L2 بخواهد به نوبه خود مجازیسازی انجام دهد. با استفاده از virsh autostart guest1، فرآیند بوت guest را ایمن کنید.
باصره (bus) مدل virtio در disk و NIC صرفاً جنبه تزئینی ندارد: دستگاههای emulated IDE و e1000 بسیار بیشتر از صفهای virtio باعث trap به hypervisor میشوند، و در حالت nesting، هزینه هر trap دو برابر است.
Networking: بخشهایی که در آموزشها نادیده گرفته میشوند
VPS شما دارای یک IP عمومی است و پشت یک شبکه (fabric) قرار دارد که آدرسهای MAC ناشناخته را فیلتر میکند. این موضوع دو پیامد دارد.
اتصال (Bridging) مهمانهای L2 به شبکه عمومی معمولاً کار نمیکند. اگر br0 را روی NIC عمومی قرار دهید و به مهمان آدرس MAC اختصاصی بدهید، خواهید دید که درخواستهای ARP ارسال میشوند اما پاسخی دریافت نمیشود؛ سوئیچ ارائهدهنده، فریمهای مربوط به یک MAC که قبلاً به شما اختصاص داده نشده را حذف میکند. اگر با این مشکل مواجه هستید، عیبیابی bridge را متوقف کنید؛ این رفتار سیستم است.
به جای آن از شبکه NAT استفاده کنید. ابزار libvirt شامل default است: virbr0، 192.168.122.0/24 و اجارههای (leases) dnsmasq؛ که باعث میشود اتصال خروجی بلافاصله برقرار شود. برای اتصال ورودی، TLS را در L1 پایان دهید و سپس درخواستها را پروکسی کنید — مسیرهای گواهینامه در ادامه از صدور گواهینامه Let's Encrypt با Certbot در Nginx گرفته شدهاند:
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;
}
}ابتدا به مهمان یک اجاره استاتیک (virsh net-edit default) اختصاص دهید تا آدرس در آن proxy_pass ثابت بماند.
رابطهای مدیریتی در اینترنت در دسترس نیستند: VNC روی پورت 5900 و رابط کاربری وب Proxmox روی پورت 8006 باید روی loopback باشند و از طریق یک تونل SSH (ssh -N -L 8006:127.0.0.1:8006 you@your-vps) یا از طریق یک VPN WireGuard خود-میزبان به VPS در دسترس باشند؛ این کار باعث میشود کل محدوده مهمانهای 192.168.122.0/24 تنها یک گام (hop) خصوصی با شما فاصله داشته باشند. فایروال را محدود نگه دارید — فقط sudo ufw allow 22,80,443/tcp، و نه هیچ چیز دیگر. اگر بلافاصله پس از فعالسازی ufw، مهمانها اتصال خروجی خود را از دست دادند، مقصر معمول DEFAULT_FORWARD_POLICY="DROP" در /etc/default/ufw است — آن را روی ACCEPT تنظیم کرده و ufw را reload کنید.
Proxmox روی یک VPS
Proxmox VE 9 در لایه زیرین از Debian 13 استفاده میکند؛ بنابراین با افزودن مخزن pve-no-subscription و بسته proxmox-ve روی یک Debian VPS نصب میشود. خطوط مربوط به مخزن (repository) و کلید امنیتی (keyring) را مستقیماً از مستندات رسمی و فعلی Proxmox بردارید؛ استفاده از URL کپی شده از یک پست قدیمی باعث شکست در فرآیند نصب میشود.
بستهها بخش دشوار کار نیستند. Proxmox انتظار دارد vmbr0 به یک NIC فیزیکی پل (bridge) شده باشد، که این موضوع مستقیماً با محدودیت فیلترینگ MAC که در بالا ذکر شد، برخورد میکند. ساختاری که روی یک VPS کار میکند، یک vmbr0 با قابلیت NAT یا مسیریابی (routed) است که به پورت فیزیکی متصل نیست، مهمانها (guests) در یک محدوده خصوصی قرار دارند، و برای هر مورد عمومی، از قوانین DNAT یا یک reverse proxy روی host استفاده میشود. در جایی که سرویسهای عمومی به جای VM از حالت container استفاده میکنند، Traefik که چندین اپلیکیشن را از طریق یک فایل Docker Compose مدیریت میکند همان وظیفه مسیریابی را با گواهیهای خودکار انجام میدهد. ابتدا از /etc/network/interfaces اسنپشات تهیه کنید: تعریف اشتباه یک bridge باعث میشود دسترسی شما به سیستمی که ممکن است کنسول آن را در دسترس نداشته باشید، قطع شود.
عملکرد، بدون پردهپوشی
حالت Nested نسبت به حالت تکسطحی کندتر است و علت این موضوع مشخص است: هزینه اصلی در دسترسی به حافظه نیست، بلکه در خروجها (exits) است. با وجود EPT/NPT، لایه L0 جداول صفحه سایهای (shadow page tables) را برای L2 نگه میدارد و عملیاتهای معمولی خواندن از حافظه با سرعت سختافزاری انجام میشوند. آنچه باعث کاهش عملکرد میشود، هر عملیاتی است که از حالت مهمان (guest mode) خارج میشود؛ مانند I/O، وقفه تایمر، MMIO و وقفههای بین پردازندهای (inter-processor interrupts)؛ زیرا هر خروج در L2 توسط L0 مدیریت میشود و ممکن است دوباره از طریق L1 بازگردانده شود. کارهای وابسته به CPU که روی دادههای موجود در RAM انجام میشوند، تقریباً مشابه حالت Native هستند؛ اما هر کاری که تحت تأثیر syscallها، بستهها (packets) و I/O دیسک باشد، تأثیر لایهها را به وضوح حس میکند.
بنابراین: در همه جا از devices نوع virtio استفاده کنید. همچنین فایل qcow2 شما روی دیسکی قرار دارد که توسط ارائهدهنده قبلاً مجازیسازی شده است؛ یعنی دو لایه thin-provisioning روی هم قرار گرفتهاند، جایی که cache=none روی دیسک مهمان، مانع از قرارگیری بلوکهای یکسان در دو page cache به طور همزمان میشود. در اینجا عدد و رقم مشخصی برای بنچمارک ارائه نمیشود: بار کاری (workload) خود را روی نمونه (instance) خودتان اندازهگیری کنید.
حالتهای خطا و رشتههایی که مشاهده خواهید کرد
INFO: /dev/kvm does not exist / KVM acceleration can NOT be used از kvm-ok. یا ماژول بارگذاری نشده است، یا flag آن در دسترس نیست. ابتدا /proc/cpuinfo را بررسی کنید.
kvm: disabled by bios در dmesg. در سیستمهای bare metal، گزینه VT-x/SVM را در firmware فعال کنید. در یک VPS، این به معنای عدم ارائه extensions توسط L0 است و هیچ تغییری در guest اثر نخواهد داشت.
modprobe: ERROR: could not insert 'kvm_intel': Operation not supported. پردازنده مورد مشاهده توسط kernel فاقد vmx است — این مجدداً یک تصمیم از سمت L0 است.
Could not access KVM kernel module: Permission denied. مشکل از دسترسیها (Permissions) است، نه سختافزار. دستور ls -l /dev/kvm باید گروه kvm و mode 660 را نشان دهد؛ خود را به آن گروه اضافه کنید و یک login shell جدید باز کنید، زیرا عضویت در گروه برای sessionهای در حال اجرا اعمال نمیشود.
kvm: Device or resource busy هنگام شروع QEMU. یک hypervisor دیگر پردازنده را در اختیار دارد: دستور lsmod را اجرا کنید، به دنبال ماژولهای vboxdrv یا VMware در کنار kvm_intel بگردید، و ماژول مورد نظر خود را unload کنید.
/var/run/libvirt/libvirt-sock: No such file or directory از virsh. سرویس (daemon) متوقف شده است: sudo systemctl enable --now libvirtd.
Proxmox: KVM virtualisation configured, but not available. یک guest دارای گزینه KVM acceleration فعال است، در حالی که host توانایی ارائه آن را ندارد. مشکل nesting را حل کنید، یا گزینه را غیرفعال کنید و از emulation استفاده کنید.
Android emulator: x86_64 emulation currently requires hardware acceleration! مجدداً /dev/kvm — معمولاً مربوط به گروه (group) است.
عدم نمایش هیچ خطایی و سرعت بسیار پایین. اگر QEMU بدون accelerator flag اجرا شود، به TCG (شبیهساز نرمافزاری خود) بازگشت میکند. این حالت صحیح است اما بسیار کند است؛ فرآیند بوت که با ثانیه سنجیده میشد، به دقیقه تبدیل میشود. از -accel kvm به صورت صریح استفاده کنید تا QEMU به جای emulation بیصدا، با خطا متوقف شود.
ناپدید شدن guest در حین اجرا. در dmesg به دنبال Out of memory: Killed process ... qemu-system-x86_64 بگردید. یک guest در سطح L2، یک process در سطح L1 است و OOM killer با آن مانند هر process دیگری برخورد میکند. RAM مربوط به L2 از تخصیص ثابت L1 استفاده میکند و امکان قرض گرفتن از host وجود ندارد.
نحوه کاربری: پشتیبانگیری، ارتقا، محدودیتها
Backups. کپی کردن فایل qcow2 یک guest در حال اجرا، منجر به ایجاد یک image خراب میشود. یا از virsh shutdown guest1 استفاده کنید و کپی بگیرید، یا یک snapshot خارجی (virsh snapshot-create-as guest1 snap1 --disk-only --atomic) ایجاد کنید تا هنگام کپی کردن فایل base (که اکنون ثابت است)، عملیات نوشتن به یک overlay منتقل شود؛ سپس با استفاده از virsh blockcommit آن را ادغام کنید. کپیها را به خارج از VPS منتقل کنید — یک snapshot روی همان دیسک، هیچ حفاظتی در برابر خرابی دیسک ندارد.
Upgrades. دستور apt full-upgrade ماژولهای جدید kvm_intel/kvm_amd را نصب میکند، اما kernel در حال اجرا تا زمانی که سیستم را reboot نکنید، همان ماژولهای قدیمی را نگه میدارد. نسخه قبلی kernel را نصب نگه دارید و پس از هر تغییر در kernel، دستور kvm-ok را مجدداً اجرا کنید: اگر host بدون vmx بالا بیاید، تنها یک boot entry تا بازگشت به حالت کارکرد صحیح فاصله دارد.
محدودیتهای مقیاسپذیری. وجود یک public IP به این معناست که تمام سرویسهای L2 از طریق یک proxy یا یک rule از نوع DNAT در L1 به دنیای بیرون متصل میشوند. قابلیت Live migration در این حالت در دسترس نیست. در صورت وجود CPU contention، مسیر nested exit اولین بخشی است که تحت فشار قرار میگیرد. همچنین، یک hypervisor با چندین guest، سیستمی است که RAM آن قبلاً مصرف شده است — nested VMها نمیتوانند با overcommit کردن، از محدودیت یک allocation ثابت فراتر بروند. وقتی یک lab از این ظرفیت فراتر میرود، راه حل استفاده از یک stack nested بلندتر نیست؛ بلکه استفاده از یک box اختصاصی است که در آن شما L0 هستید و هیچکدام از این محدودیتها اعمال نمیشوند.
FAQ
Do I need nested virtualization to run Docker on a VPS?
No. Containers share your VPS kernel and never open /dev/kvm, so a plain instance with no vmx or svm flag runs Docker and Docker Compose fine. Nesting only matters when you want a second kernel: a Proxmox lab, a Windows guest, Firecracker microVMs, an Android emulator, or CI runners that boot VM images.
How do I check whether my VPS supports nested virtualization?
Run grep -o -E 'vmx|svm' /proc/cpuinfo | sort -u, then kvm-ok from the cpu-checker package. A usable instance prints vmx (Intel) or svm (AMD), kvm-ok reports KVM acceleration can be used, and /dev/kvm exists with group kvm and mode 660. Ignore /sys/module/kvm_intel/parameters/nested for this question — that file describes your own KVM module, not what the provider's hypervisor exposed to you.
Why do most VPS providers disable nested virtualization?
Exposing vmx means handing the guest a CPU model that carries the flag, and a guest that depends on those CPU features cannot be live-migrated onto a machine whose CPU lacks them — a provider that drains nodes by moving customers around gives that up. The nested VMX/SVM code paths also carry a long CVE history. Some hosts still enable it per-VM on request, and others document nesting as a plan feature.
My nested VM has no network on the public bridge. What is wrong?
The provider's switch drops frames from a MAC address it never leased you, so an L2 guest bridged onto the public NIC sends ARP and hears nothing back. Stop debugging br0 — use libvirt's NAT default network (virbr0, 192.168.122.0/24), give the guest a static lease, and publish anything public through a reverse proxy or DNAT rule on the VPS itself.
How much slower is a nested VM?
The cost lands on VM exits, not on memory access. With EPT/NPT active, ordinary reads and writes inside L2 run at hardware speed, while I/O, timer interrupts, MMIO and IPIs are handled by L0 and may be bounced back through L1. CPU-bound work over data already in RAM looks close to native; syscall-, packet- and disk-heavy workloads feel every layer. Use virtio devices everywhere and cache=none on guest disks, then measure your own workload.