اجرای Proxmox روی VPS: آیا Nested Virtualization ممکن است؟
بسیاری از سرویسدهندگان VPS پرچم vmx را مسدود میکنند. با دستور kvm-ok وضعیت سرور خود را بررسی کنید و ببینید آیا اجرای Proxmox یا KVM روی ماشین مجازی شما ممکن است یا خیر.
پاسخ کوتاه
مجازیسازی تو در تو (Nested virtualization) به معنای اجرای یک هایپروایزر در داخل یک ماشین مجازی است: VPS شما در حال حاضر یک مهمان است و شما میخواهید که خودتان میزبان مهمانهای دیگری باشید. این قابلیت تنها زمانی کار میکند که هایپروایزر ارائهدهندهٔ خدمات شما، بهطور عمدی افزونههای مجازیسازی CPU را در اختیار instance شما قرار دهد. برای بررسی، /proc/cpuinfo را برای پرچم vmx (در اینتل) یا svm (در ایامدی) چک کنید؛ اگر هیچکدام ظاهر نشدند، هیچ پیکربندیای در داخل VPS این مشکل را حل نخواهد کرد.
ابتدا یک نکته برای مدیریت انتظارات: Docker به هیچکدام از اینها نیاز ندارد. کانتینرها از هسته (kernel) VPS شما استفاده میکنند و هرگز با /dev/kvm تعاملی ندارند. اگر هدف واقعی شما «اجرای چندین سرویس در کانتینر روی سرور» است، شما در حال حاضر ابزار لازم را در اختیار دارید. مجازیسازی تو در تو زمانی اهمیت پیدا میکند که بخواهید یک هستهٔ دوم، یک آزمایشگاه Proxmox، یک مهمان ویندوزی، میکرو ماشینهای مجازی Firecracker، شبیهساز اندروید، یک محیط تست Kubernetes متشکل از ماشینهای مجازی واقعی، یا CI runnerهایی داشته باشید که ایمیجهای ماشین مجازی را بوت میکنند.
چه چیزی در واقع بهصورت تو در تو (nested) اجرا میشود
سه لایه وجود دارد:
- L0، هایپروایزر ارائهدهنده، روی سختافزار اصلی (bare metal). شما به آن دسترسی ندارید.
- L1، همان VPS شما. برای L0، این فقط یک مهمان (guest) است.
- L2، ماشین مجازی (VM) که میخواهید داخل VPS خود اجرا کنید.
مجازیسازی سختافزاری شامل VT-x (فلگ vmx) بهعلاوه EPT در اینتل، و AMD-V / SVM (svm) بهعلاوه RVI/NPT در AMD است. یک هایپروایزر از این دستورات استفاده میکند تا وارد حالت مهمان شود و به CPU اجازه دهد همزمان دو جدول صفحه (page table) را پیمایش کند.
هیچکدام از اینها برای بازگشتپذیری (re-entrant) طراحی نشدهاند، بنابراین nesting شبیهسازی میشود: وقتی L1 یک دستور VMX را اجرا میکند، یک trap به L0 ارسال میشود؛ سپس L0 به نمایندگی از L1، ساختارهای سایه (shadow structures) را برای L2 مدیریت میکند. KVM این کار را بهخوبی انجام میدهد، اما این L0 است که در هر خروج (exit) کار اضافه انجام میدهد؛ به همین دلیل است که ارائهدهنده باید این قابلیت را فعال کند.
برای داشتن یک L2 شتابیافته (accelerated)، باید هر دو شرط زیر برقرار باشد:
- ماژول KVM در L0 با فلگ
nested=1بارگذاری شده باشد. - L0 یک مدل CPU به VPS شما اختصاص دهد که شامل این فلگ باشد؛
<cpu mode='host-passthrough'/>در libvirt،cpu: hostدر Proxmox، و-cpu hostدر QEMU خام. یک مدل شبیهسازیشده عمومی (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 وجود دارد. اگر فلگ موجود است اما گره دستگاه (device node) وجود ندارد، ماژول را بهصورت دستی بارگذاری کرده و لاگ هسته (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 میتواند یک لایه سوم را nest کند یا خیر. این فایل هیچ چیزی درباره اینکه آیا 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ها را خاموش کنید.
چرا اکثر میزبانهای VPS آن را غیرفعال میگذارند
- مهاجرت زنده (Live migration). ارائه
vmxبه شما به معنای نمایش یک مدل CPU است که این پرچم را حمل میکند، و یک مهمان (guest) که به این ویژگیهای CPU وابسته است، نمیتواند بهطور ایمن به ماشینی که فاقد این ویژگیهاست مهاجرت کند. میزبانی که با مهاجرت دادن مشتریان، گرهها (nodes) را تخلیه میکند، به محض فعالسازی nesting این قابلیت را از دست میدهد. - سطح حمله (Attack surface). مسیرهای nested VMX/SVM از پیچیدهترین بخشهای کد در لایه مجازیسازی هسته (kernel) هستند و تاریخچهای از CVEها را به همراه دارند.
- لایه L0 ممکن است KVM نباشد. اگر
systemd-detect-virtخروجیvmware،xenیاmicrosoftرا نمایش دهد، قوانین nesting مربوط به آن پشته (stack) است، نه KVM.
پرچمی روی instance خود نمیبینید؟ از پشتیبانی بپرسید (برخی آن را برای هر VM بهصورت جداگانه فعال میکنند)، طرحی را انتخاب کنید که nesting را مستند کرده باشد، یا به یک سرور اختصاصی (dedicated box) مهاجرت کنید. ادامه این مطلب فرض را بر این میگذارد که شما دسترسی root روی ماشینی دارید که این پرچم را نمایش میدهد.
اجرای یک guest لایه 2 با 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'نیازی به نشست گرافیکی نیست. نصب سریال مدتی طول میکشد، بنابراین آن را درون یک shell پایدار شروع کنید: همان گردشکار tmux که نشستهای Claude Code را روی یک VPS زنده نگه میدارد، یک کنسول virt-install را نیز در صورت قطع اتصال SSH متصل نگه میدارد. اگر --os-variant debian13 رد شد، به این دلیل است که osinfo-db شما قدیمیتر از این نسخه است؛ دستور osinfo-query os را اجرا کرده و نامی را انتخاب کنید که وجود دارد. --cpu host-passthrough قابلیت vmx را به لایه 2 منتقل میکند؛ این کار تنها در صورتی لازم است که لایه 2 خود نیاز به مجازیسازی داشته باشد. با استفاده از virsh autostart guest1، بوت guest را ایمن کنید.
استفاده از باس virtio برای دیسک و کارت شبکه صرفاً جنبه ظاهری ندارد: دستگاههای شبیهسازیشده IDE و e1000 بسیار بیشتر از صفهای virtio باعث ایجاد trap در هایپروایزر میشوند و در حالت nesting، هزینه هر trap دو بار پرداخت میشود.
شبکه: بخشی که در آموزشها نادیده گرفته میشود
سرور مجازی (VPS) شما یک IP عمومی دارد و پشت شبکهای قرار گرفته است که آدرسهای MAC ناشناس را فیلتر میکند. این موضوع دو پیامد دارد.
پلزدن (Bridging) مهمانهای L2 به شبکه عمومی معمولاً کار نمیکند. اگر br0 را روی کارت شبکه عمومی (NIC) قرار دهید و به مهمان یک MAC اختصاصی بدهید، خواهید دید که درخواستهای ARP ارسال میشوند اما پاسخی دریافت نمیکنید؛ سوئیچ ارائهدهنده، فریمهایی را که از MACای ارسال شده که به شما اجاره نداده است، مسدود میکند. اگر با این مشکل مواجه شدید، عیبیابی پل را متوقف کنید؛ این ماهیت عملکرد شبکه است.
از شبکه NAT استفاده کنید. libvirt شامل default است: virbr0، 192.168.122.0/24، اجارههای 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;
}
}ابتدا یک اجاره ثابت (static lease) به مهمان اختصاص دهید (virsh net-edit default) تا آدرس در آن proxy_pass ثابت بماند.
رابطهای مدیریتی را از اینترنت دور نگه دارید: VNC روی پورت 5900 و رابط وب Proxmox روی پورت 8006 باید روی loopback باشند و از طریق تونل SSH (ssh -N -L 8006:127.0.0.1:8006 you@your-vps) یا یک شبکه خصوصی WireGuard روی VPS به آنها دسترسی پیدا کنید، که کل محدوده مهمان 192.168.122.0/24 را در یک گام خصوصی در دسترس قرار میدهد. فایروال را محدود نگه دارید، sudo ufw allow 22,80,443/tcp، و هیچ چیز دیگری را باز نگذارید. اگر مهمانها بلافاصله پس از فعالسازی ufw اتصال خروجی خود را از دست دادند، مقصر معمولاً DEFAULT_FORWARD_POLICY="DROP" در /etc/default/ufw است؛ آن را روی ACCEPT تنظیم کرده و ufw را دوباره بارگذاری کنید.
اجرای Proxmox روی VPS
پایهٔ Proxmox VE 9 سیستمعامل Debian 13 است، بنابراین با افزودن مخزن pve-no-subscription و بستهٔ proxmox-ve روی یک VPS مبتنی بر Debian نصب میشود. خطوط مربوط به مخزن و keyring را مستقیماً از مستندات فعلی Proxmox دریافت کنید؛ استفاده از URLهای کپیشده از پستهای وبلاگی قدیمی، فرآیند نصب را مختل میکند. پیش از آنکه یک شب را صرف پیکربندی شبکه کنید، ارزش دارد که بررسی کنید آیا اصلاً Proxmox برای سختافزار اجارهای مناسب است یا خیر؛ مقایسهٔ هزینه و قابلیتهای یک سرور Proxmox خانگی با یک VPS اجارهای نسخهای از این پرسش است که محاسبات مربوط به توان مصرفی و سختافزار در آن انجام شده است.
بخش دشوار کار، بستهها نیستند. Proxmox انتظار دارد vmbr0 به یک کارت شبکه فیزیکی (NIC) متصل (bridge) باشد که مستقیماً به بنبست فیلترینگ MAC که پیشتر ذکر شد، ختم میشود. ساختاری که روی VPS کار میکند، یک vmbr0 مبتنی بر NAT یا مسیریابی است که به هیچ پورت فیزیکی متصل نیست؛ در این حالت، مهمانها در یک رنج شبکه خصوصی قرار میگیرند و برای هر سرویس عمومی، از قوانین DNAT یا یک reverse proxy روی میزبان استفاده میشود. در مواردی که سرویسهای عمومی به جای ماشین مجازی (VM)، کانتینر هستند، استفاده از Traefik برای مدیریت چندین برنامه از یک فایل Docker Compose همان وظیفه مسیریابی را با گواهیهای خودکار انجام میدهد. ابتدا از /etc/network/interfaces اسنپشات بگیرید: یک تعریف اشتباه برای bridge میتواند دسترسی شما را به ماشینی که ممکن است کنسول آن را در اختیار نداشته باشید، بهطور کامل قطع کند.
عملکرد، بدون اغراق
مجازیسازی تو در تو (Nested) نسبت به تکلایه کندتر است و این کندی ناشی از یک مکانیسم خاص است: هزینه اصلی در دسترسی به حافظه نیست، بلکه در خروجها (exits) است. با وجود EPT/NPT، لایه L0 جداول صفحه سایه (shadow page tables) را برای L2 حفظ میکند و خواندنهای عادی از حافظه با سرعت سختافزار انجام میشوند. آنچه هزینهبر است، هر عملیاتی است که باعث خروج از حالت مهمان (guest mode) میشود؛ مانند I/O، وقفههای تایمر، MMIO و وقفههای بینپردازندهای، زیرا یک خروج L2 توسط L0 مدیریت شده و ممکن است به L1 بازگردانده شود. پردازشهای متکی بر CPU که دادههای آنها از قبل در RAM موجود است، عملکردی نزدیک به حالت بومی (native) دارند؛ اما هر کاری که تحت تأثیر syscallها، بستههای شبکه و I/O دیسک باشد، تأثیر لایهها را نشان میدهد.
بنابراین: از دستگاههای virtio در همه جا استفاده کنید. فایل qcow2 شما روی دیسکی قرار دارد که ارائهدهنده قبلاً آن را مجازیسازی کرده است؛ یعنی دو لایه thin-provisioning روی هم قرار گرفتهاند، جایی که استفاده از 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. روی سختافزار فیزیکی (bare metal)، گزینه VT-x/SVM را در تنظیمات firmware فعال کنید. در محیط VPS، این پیام به این معناست که لایه L0 قابلیتهای مجازیسازی را به شما ارائه نمیدهد و هیچ دستوری در سیستمعامل مهمان (guest) این وضعیت را تغییر نخواهد داد.
modprobe: ERROR: could not insert 'kvm_intel': Operation not supported. پردازندهای که هسته (kernel) شما میبیند فاقد vmx است؛ این نیز تصمیمی است که در لایه L0 گرفته شده است.
Could not access KVM kernel module: Permission denied. مشکل از مجوزهاست، نه سختافزار. ls -l /dev/kvm باید گروه kvm و حالت 660 را نشان دهد؛ خودتان را به آن گروه اضافه کنید و یک نشست (shell) جدید باز کنید، زیرا عضویت در گروه برای نشستهای در حال اجرا اعمال نمیشود.
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. قابلیت شتابدهنده KVM برای یک ماشین مجازی روی میزبانی فعال شده که قادر به ارائه آن نیست. قابلیت nesting را اصلاح کنید یا تیک آن را بردارید و شبیهسازی (emulation) را بپذیرید.
شبیهساز Android: x86_64 emulation currently requires hardware acceleration! دوباره همان /dev/kvm، که معمولاً به دلیل مشکل عضویت در گروه است.
هیچ خطایی وجود ندارد اما همهچیز بسیار کند است. QEMU بدون فلگ شتابدهنده به TCG (شبیهساز نرمافزاری خود) بازمیگردد. این حالت صحیح است اما بسیار کند عمل میکند؛ زمان بوت که باید چند ثانیه باشد، به چند دقیقه میرسد. فلگ -accel kvm را صراحتاً ارسال کنید تا QEMU بهجای شبیهسازی بیسروصدا، با خطا متوقف شود.
یک ماشین مجازی در حین اجرا ناپدید میشود. در dmesg به دنبال Out of memory: Killed process ... qemu-system-x86_64 بگردید. یک ماشین مجازی L2 در واقع یک پردازش در لایه L1 است و OOM killer با آن مانند سایر پردازشها رفتار میکند. رم اختصاصیافته به L2 از سهمیه ثابت L1 تأمین میشود و امکان قرض گرفتن از میزبان (host) وجود ندارد.
عملیات: پشتیبانگیری، ارتقا، محدودیتها
پشتیبانگیری. کپی کردن فایل qcow2 یک guest در حال اجرا، منجر به ایجاد یک image خراب میشود. یا باید آن را virsh shutdown guest1 کنید و سپس کپی بگیرید، یا یک snapshot خارجی (virsh snapshot-create-as guest1 snap1 --disk-only --atomic) ایجاد کنید تا عملیات نوشتن به یک overlay هدایت شود؛ در این حالت میتوانید از base ثابت کپی بگیرید و سپس با استفاده از virsh blockcommit آن را ادغام کنید. نسخههای پشتیبان را از VPS خارج کنید؛ snapshot روی همان دیسک در برابر هیچ خطری محافظت ایجاد نمیکند.
ارتقا. دستور apt full-upgrade ماژولهای جدید kvm_intel/kvm_amd را نصب میکند، اما kernel در حال اجرا تا زمان reboot از ماژولهای قدیمی استفاده میکند. kernel قبلی را نصب نگه دارید و پس از هر تغییر در kernel، دستور kvm-ok را دوباره اجرا کنید: در این صورت، اگر هاستی بدون vmx بالا آمد، تنها با یک boot entry فاصله تا بازگشت به حالت عادی قرار دارد.
محدودیتهای مقیاسپذیری. داشتن یک IP عمومی به این معناست که هر سرویس L2 باید از طریق یک proxy یا یک قانون DNAT در L1 به اینترنت دسترسی پیدا کند. قابلیت Live migration در این مدل وجود ندارد. در شرایط فشار بر CPU، مسیر nested exit اولین بخشی است که دچار کندی میشود. همچنین، hypervisor با چندین guest، ماشینی است که RAM آن از قبل تخصیص یافته است؛ VMهای تو در تو (nested) نمیتوانند با overcommit از محدودیت تخصیص ثابت فراتر بروند. زمانی که یک محیط آزمایشگاهی از این سطح فراتر رفت، راهکار، افزایش ارتفاع stack تو در تو نیست؛ بلکه استفاده از یک سرور اختصاصی است که در آن شما L0 هستید و هیچکدام از این محدودیتها اعمال نمیشود.
FAQ
آیا برای اجرای Docker روی VPS به nested virtualization نیاز دارم؟
خیر. کانتینرها از هسته (kernel) سیستمعامل VPS شما استفاده میکنند و هرگز /dev/kvm را باز نمیکنند، بنابراین یک نمونه معمولی بدون هیچ پرچم vmx یا svm بهخوبی Docker و Docker Compose را اجرا میکند. قابلیت nesting فقط زمانی اهمیت دارد که به هسته دوم نیاز داشته باشید: برای مثال در آزمایشگاه Proxmox، مهمان ویندوزی، Firecracker microVMs، شبیهساز اندروید یا CI runnerهایی که ایمیجهای VM را بوت میکنند.
چگونه بررسی کنم که VPS من از nested virtualization پشتیبانی میکند؟
دستور grep -o -E 'vmx|svm' /proc/cpuinfo | sort -u و سپس kvm-ok از بسته cpu-checker را اجرا کنید. یک نمونه قابلاستفاده، خروجی vmx (برای Intel) یا svm (برای AMD) را چاپ میکند، kvm-ok مقدار KVM acceleration can be used را گزارش میدهد و /dev/kvm با گروه kvm و دسترسی 660 وجود دارد. برای این پرسش، /sys/module/kvm_intel/parameters/nested را نادیده بگیرید؛ آن فایل ماژول KVM خودتان را توصیف میکند، نه آنچه هایپروایزر ارائهدهنده به شما ارائه داده است.
چرا اکثر ارائهدهندگان VPS قابلیت nested virtualization را غیرفعال میکنند؟
ارائه vmx به این معناست که به مهمان یک مدل CPU داده شود که آن پرچم را دارد؛ مهمانی که به این ویژگیهای CPU وابسته است، نمیتواند به ماشینی که فاقد آن ویژگیهاست live-migrate شود. ارائهدهندهای که با جابهجایی مشتریان، گرهها را تخلیه میکند، این قابلیت را از دست میدهد. مسیرهای کد nested VMX/SVM همچنین تاریخچه طولانی از CVE دارند. برخی میزبانها همچنان آن را در صورت درخواست برای هر VM فعال میکنند و برخی دیگر nesting را به عنوان یک ویژگی در پلنهای خود مستند کردهاند.
ماشین مجازی nested من روی bridge عمومی شبکه ندارد. مشکل چیست؟
سوییچ ارائهدهنده، فریمهایی را که از آدرس MAC اجارهنشده ارسال میشوند، حذف میکند؛ بنابراین یک مهمان L2 که روی NIC عمومی پل شده است، ARP ارسال میکند اما پاسخی دریافت نمیکند. عیبیابی br0 را متوقف کنید، از شبکه NAT در libvirt (default، virbr0، 192.168.122.0/24) استفاده کنید، به مهمان یک lease ایستا بدهید و هر سرویس عمومی را از طریق یک reverse proxy یا قانون DNAT روی خودِ VPS منتشر کنید.
یک ماشین مجازی nested چقدر کندتر است؟
هزینه این کار به VM exitها مربوط میشود، نه دسترسی به حافظه. با فعال بودن EPT/NPT، خواندن و نوشتنهای معمولی در L2 با سرعت سختافزار انجام میشود، در حالی که I/O، وقفههای تایمر، MMIO و IPIها توسط L0 مدیریت میشوند و ممکن است از طریق L1 بازگردانده شوند. کارهای متکی به CPU که دادههایشان در RAM موجود است، نزدیک به سرعت native عمل میکنند؛ اما بارهای کاری سنگین از نظر syscall، بسته شبکه و دیسک، تأثیر هر لایه را حس میکنند. از دستگاههای virtio در همه جا و cache=none روی دیسکهای مهمان استفاده کنید، سپس بار کاری خود را اندازهگیری کنید.