SSD Nodes Learn
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-07-22

محاكاة افتراضية متداخلة على VPS: KVM وProxmox

تحقّق مما إذا كان VPS لديك يوفّر VT-x أو AMD-V، فعّل KVM المتداخل، ثم شغّل Proxmox أو Windows داخل مُشرِف افتراضي ضيف، مع الأخطاء التي ستواجهها فعلاً.

الإجابة المختصرة

المحاكاة الافتراضية المتداخلة (nested virtualization) هي أن يعمل مُشرِف افتراضي (hypervisor) بالكامل داخل آلة افتراضية: خادم VPS لديك هو أصلًا ضيف عند مُشرِف مزوّد الخدمة، وأنت تريد أن يستضيف بدوره ضيوفًا خاصة به. لا يعمل هذا إلا حين يكشف مُشرِف مزوّد الخدمة عمدًا امتدادات المحاكاة الافتراضية في المعالج لمثيلك — تحقّق في /proc/cpuinfo من وجود العلامة vmx (على Intel) أو svm (على AMD)؛ فإن لم تظهر أي منهما، فلن يصلح أي إعداد تُجريه داخل الـ VPS هذا الأمر.

لنضبط التوقعات أولًا: Docker لا يحتاج إلى أي شيء من هذا. فالحاويات تتشارك نواة VPS لديك ولا تلمس /dev/kvm إطلاقًا. إن كان هدفك الحقيقي هو «تشغيل عدة خدمات في حاويات على خادمي»، فأنت تملك بالفعل كل ما تحتاج إليه. التداخل (nesting) يهمّ حين تريد نواة ثانية — معمل Proxmox، أو ضيف Windows، أو آلات Firecracker microVM دقيقة، أو محاكي Android، أو بيئة اختبار Kubernetes من آلات افتراضية حقيقية، أو مُشغّلات CI (CI runners) تُقلع صور آلات افتراضية.

ما الذي يتداخل بالفعل

ثلاث طبقات:

  • L0 — مُشرِف مزوّد الخدمة، على المعدن العاري (bare metal). لا تملك أي وصول إليه.
  • L1 — خادم VPS الخاص بك. بالنسبة إلى L0 هذا مجرد ضيف.
  • L2 — الآلة الافتراضية التي تريد تشغيلها داخل VPS الخاص بك.

المحاكاة الافتراضية العتادية (hardware virtualization) هي VT-x (علامة vmx) مع EPT على Intel، وAMD-V / SVM (svm) مع RVI/NPT على AMD. يستخدم المُشرِف الافتراضي هذه التعليمات للدخول في نمط الضيف (guest mode) وللسماح للمعالج باجتياز جدولَي صفحات في آن واحد.

لم تُصمَّم أي منهما لتكون قابلة لإعادة الدخول (re-entrant)، لذلك يُحاكى التداخل: حين تنفّذ L1 تعليمة VMX، تنتقل (trap) إلى L0، التي تحافظ على البنى الظلية (shadow structures) الخاصة بـ L2 نيابةً عن L1. يقوم KVM بهذا جيدًا، لكن L0 هي من تؤدي العمل الإضافي في كل عملية خروج (exit) — ولهذا يجب أن يختار مزوّد الخدمة تفعيل هذا الأمر بنفسه.

لا بد من تحقّق شرطين معًا كي تحصل على L2 مُسرَّع:

  1. وحدة KVM في L0 محمّلة بالخيار nested=1.
  2. تمنح L0 خادم VPS لديك طراز معالج يحمل العلامة — <cpu mode='host-passthrough'/> في libvirt، أو cpu: host في Proxmox، أو -cpu host في QEMU الخام. أما الطراز المُحاكى العام (qemu64، kvm64) فيخفي vmx حتى حين يكون التداخل مفعّلًا عالميًا.

تحقّق من 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. إن كانت العلامة موجودة لكن عقدة الجهاز غير موجودة، فحمّل الوحدة يدويًا واقرأ سجل النواة:

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 أن يُدخِل مستوى ثالثًا من التداخل. إنه لا يخبرك بشيء عمّا إذا كانت 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_intel

يُرفض إزالة الوحدة طالما أن آلة افتراضية تعمل، لذا أوقف الضيوف أولًا.

لماذا يترك معظم مزوّدي VPS هذا الخيار معطّلًا

  • الترحيل الحي (live migration). منحك vmx يعني كشف طراز معالج يحمل العلامة، وضيف يعتمد على ميزات المعالج تلك لا يمكن ترحيله بأمان إلى آلة يفتقر معالجها إليها. مزوّد يُفرغ عقده (nodes) بترحيل عملائه يتخلى عن هذه القدرة بمجرد أن يفعّل التداخل.
  • سطح الهجوم (attack surface). مسارات VMX/SVM المتداخلة من بين أكثر الشيفرات تعقيدًا في طبقة المحاكاة الافتراضية الخاصة بالنواة، ولها تاريخ من الثغرات الأمنية الموثقة (CVE) يوازي ذلك.
  • قد لا تكون L0 قائمة على KVM. إن طبعت systemd-detect-virt القيمة vmware أو xen أو microsoft، فقواعد التداخل هي قواعد تلك المنصة، لا قواعد KVM.

لا توجد علامة على مثيلك؟ اسأل الدعم الفني (بعض المزوّدين يفعّلها لكل آلة افتراضية على حدة)، أو اختر خطة توثّق دعم التداخل، أو انتقل إلى خادم مخصص. تفترض بقية هذا المقال أن لديك صلاحيات root على آلة تُظهر العلامة.

تشغيل ضيف 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'

لا حاجة إلى جلسة رسومية. يستغرق التثبيت التسلسلي (serial) وقتًا، فابدأه داخل صَدَفة (shell) دائمة: نفس أسلوب عمل tmux الذي يبقي جلسات Claude Code حية على خادم VPS يُبقي طرفية virt-install متصلة رغم انقطاع اتصال SSH. إن رُفض --os-variant debian13، فإن osinfo-db لديك أقدم من هذا الإصدار — نفّذ osinfo-query os واختر اسمًا موجودًا فعليًا. الخيار --cpu host-passthrough ينقل vmx إلى L2، وهو لازم فقط إذا كان على L2 أن تُجري محاكاة افتراضية بدورها. اجعل الضيف آمنًا عند الإقلاع بالأمر virsh autostart guest1.

ناقل virtio على القرص وبطاقة الشبكة ليس زخرفة: فأجهزة IDE وe1000 المُحاكاة تنتقل إلى المُشرِف الافتراضي أكثر بكثير مما تفعله طوابير virtio، وتحت التداخل، يُدفع ثمن كل انتقال مرتين.

الشبكة: الجزء الذي تتجاهله الدروس

خادم VPS لديك يملك عنوان IP عامًا واحدًا، ويقع خلف نسيج شبكي (fabric) يُصفّي عناوين MAC غير المعروفة. يترتب على ذلك أمران.

ربط ضيوف L2 بجسر (bridge) على الشبكة العامة عادةً لن ينجح. ضع br0 على بطاقة الشبكة العامة، وامنح الضيف عنوان MAC خاصًا به، وسترى طلبات ARP تخرج ولا يعود منها شيء — فمِفتاح (switch) مزوّد الخدمة يُسقط الإطارات (frames) الصادرة من عنوان MAC لم يمنحك إياه قط. إن كان هذا هو عرضك، فتوقف عن تصحيح خلل الجسر؛ فهذه هي الآلية نفسها.

استخدم شبكة NAT بدلًا من ذلك. تأتي libvirt بشبكة default جاهزة: virbr0، و192.168.122.0/24، وإيجارات (leases) dnsmasq، والاتصال الصادر يعمل فورًا. أما بالنسبة للاتصال الوارد، فأنهِ TLS على L1 ثم مرّره عبر proxy — مسارات الشهادات أدناه مأخوذة من إصدار شهادة 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 VPN مستضافة ذاتيًا إلى الـ 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، لذا يُثبَّت على VPS يعمل بـ Debian بإضافة مستودع pve-no-subscription وحزمة proxmox-ve. خذ أسطر المستودع وحلقة المفاتيح (keyring) من توثيق Proxmox الرسمي الحالي — فأي رابط منسوخ من تدوينة قديمة يُفسد التثبيت.

الحزم ليست الجزء الصعب. يتوقّع Proxmox أن يكون vmbr0 جسرًا مربوطًا ببطاقة شبكة فعلية، وهذا يقودك مباشرة إلى مأزق تصفية MAC المذكور أعلاه. الإعداد الذي ينجح على VPS هو vmbr0 بنمط NAT أو موجَّه (routed) دون أي منفذ فعلي مرتبط به، وضيوف على نطاق خاص، وقواعد DNAT أو reverse proxy على المضيف لأي شيء عام. وحين تكون الخدمات المواجهة للعامة حاويات لا آلات افتراضية، فإن Traefik في واجهة عدة تطبيقات من ملف Docker Compose واحد يغطي مهمة التوجيه نفسها مع شهادات تلقائية. خذ نسخة احتياطية من /etc/network/interfaces أولًا: فتعريف جسر خاطئ قد يقفل عليك آلة قد لا تملك طرفيتها (console).

الأداء، بصراحة

التداخل أبطأ من مستوى واحد، والآلية محددة لا منتشرة: التكلفة لا تقع على الوصول إلى الذاكرة، بل على عمليات الخروج (exits). مع وجود EPT/NPT، تحافظ L0 على جداول صفحات ظلية لـ L2، وتعمل قراءات الذاكرة العادية بسرعة العتاد. ما يصبح مكلفًا هو كل عملية تغادر نمط الضيف — الإدخال/الإخراج، ومقاطعات المؤقت، وMMIO، والمقاطعات بين المعالجات — لأن خروج L2 تتولاه L0 وقد يُعاد توجيهه عبر L1. العمل المرتبط بالمعالج على بيانات موجودة أصلًا في RAM يبدو قريبًا من الأداء الأصلي (native)؛ أما ما يهيمن عليه استدعاءات النظام (syscalls) والحزم والإدخال/الإخراج على القرص فيشعر بوطأة الطبقات.

الخلاصة: استخدم أجهزة virtio في كل مكان. وملف qcow2 لديك يقيم على قرص سبق للمزوّد أن جعله افتراضيًا — أي طبقتين من التخصيص الرشيق (thin provisioning) متراكبتين، حيث يمنع cache=none على قرص الضيف وجود الكتل نفسها في مخبأي صفحات (page caches) في آن واحد. لا أرقام قياس أداء هنا: قِس حِمل عملك الخاص على مثيلك الخاص.

أنماط الفشل، والنصوص التي ستراها

INFO: /dev/kvm does not exist / KVM acceleration can NOT be used من kvm-ok. إما أن الوحدة غير محمّلة، أو أن العلامة غير مكشوفة. تحقق من /proc/cpuinfo أولًا.

kvm: disabled by bios في dmesg. على المعدن العاري، بدّل مفتاح VT-x/SVM في البرامج الثابتة (firmware). أما داخل VPS فهذا يعني أن L0 لا تمنحك الامتدادات، ولا شيء تكتبه داخل الضيف سيغيّر ذلك.

modprobe: ERROR: could not insert 'kvm_intel': Operation not supported. المعالج الذي تراه نواتك لا يحمل vmx — وهذا أيضًا قرار من L0.

Could not access KVM kernel module: Permission denied. المشكلة صلاحيات لا عتاد. يجب أن يُظهر ls -l /dev/kvm المجموعة kvm والوضع 660؛ أضف نفسك إلى تلك المجموعة وابدأ جلسة دخول جديدة، لأن الانتماء إلى مجموعة لا يسري على جلسة تعمل بالفعل.

kvm: Device or resource busy عند بدء QEMU. وحدة مُشرِف افتراضي أخرى تحتكر المعالج: نفّذ lsmod، وابحث عن vboxdrv أو وحدات VMware إلى جانب kvm_intel، وأزل الوحدة التي لا تريدها.

/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 على مضيف لا يستطيع توفيره. أصلح التداخل، أو ألغِ الخيار واقبل المحاكاة (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 — لا اقتراض من المضيف.

تشغيله فعليًا: النسخ الاحتياطي، الترقيات، الحدود

النسخ الاحتياطي. نسخ ملف qcow2 لضيف يعمل يمنحك صورة تالفة. إما أن تنفّذ virsh shutdown guest1 ثم تنسخ، أو تأخذ لقطة (snapshot) خارجية (virsh snapshot-create-as guest1 snap1 --disk-only --atomic) بحيث تُحوَّل الكتابات إلى طبقة تراكب (overlay) بينما تنسخ القاعدة التي أصبحت الآن ثابتة، ثم تدمجها لاحقًا بالأمر virsh blockcommit. انقل النسخ إلى خارج VPS — فلقطة على القرص نفسه لا تحميك من شيء.

الترقيات. يثبّت apt full-upgrade وحدات kvm_intel/kvm_amd جديدة، لكن النواة التي تعمل تبقي على القديمة حتى تعيد الإقلاع. أبقِ النواة السابقة مثبّتة وأعد تشغيل kvm-ok بعد كل تغيير للنواة: فمضيف يعود دون vmx يكون حينها على بعد مُدخل إقلاع واحد من العمل من جديد.

أين يتوقف هذا عن التوسّع. عنوان IP عام واحد يعني أن كل خدمة على L2 تصل إلى العالم عبر proxy أو قاعدة DNAT على L1. الترحيل الحي ليس مطروحًا. وعند تنافس المعالج (CPU contention)، يكون مسار الخروج المتداخل أول ما يشعر بذلك. ومُشرِف افتراضي يحمل عدة ضيوف هو آلة أنفقتَ ذاكرتها بالفعل — فالآلات الافتراضية المتداخلة لا يمكنها أن تتجاوز حدود تخصيص ثابت بالإفراط في التخصيص (overcommit). حين يكبر المعمل عن هذا الحد، لا يكون الحل مزيدًا من طبقات التداخل؛ بل خادم مخصص تكون فيه أنت L0 ولا شيء من هذا ينطبق.

FAQ

هل أحتاج إلى المحاكاة الافتراضية المتداخلة لتشغيل Docker على VPS؟

لا. الحاويات تتشارك نواة VPS لديك ولا تفتح /dev/kvm أبدًا، لذا فإن مثيلًا عاديًا بلا علامة vmx أو svm يشغّل Docker وDocker Compose دون أي مشكلة. التداخل يهمّ فقط حين تريد نواة ثانية: معمل Proxmox، أو ضيف Windows، أو آلات Firecracker microVM، أو محاكي Android، أو مُشغّلات CI تُقلع صور آلات افتراضية.

كيف أتحقق مما إذا كان VPS لدي يدعم المحاكاة الافتراضية المتداخلة؟

نفّذ 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 المحاكاة الافتراضية المتداخلة؟

كشف vmx يعني منح الضيف طراز معالج يحمل العلامة، وضيف يعتمد على ميزات المعالج تلك لا يمكن ترحيله ترحيلًا حيًا إلى آلة يفتقر معالجها إليها — ومزوّد يُفرغ عقده بترحيل عملائه يتخلى عن هذه القدرة. كما تحمل مسارات شيفرة VMX/SVM المتداخلة تاريخًا طويلًا من الثغرات الموثقة (CVE). بعض المزوّدين ما زالوا يفعّلونها لكل آلة افتراضية عند الطلب، وآخرون يوثّقون التداخل كميزة ضمن خططهم.

آلتي الافتراضية المتداخلة بلا شبكة على الجسر العام. ما الخطأ؟

مِفتاح (switch) المزوّد يُسقط الإطارات القادمة من عنوان MAC لم يمنحك إياه قط، لذا فإن ضيف L2 المربوط بجسر على بطاقة الشبكة العامة يرسل ARP ولا يسمع أي رد. توقف عن تصحيح خلل br0 — استخدم شبكة NAT الافتراضية default في libvirt (virbr0، 192.168.122.0/24)، وامنح الضيف إيجارًا ثابتًا، وانشر أي شيء عام عبر reverse proxy أو قاعدة DNAT على VPS نفسه.

ما مقدار البطء الذي تسببه الآلة الافتراضية المتداخلة؟

التكلفة تقع على عمليات خروج الآلة الافتراضية (VM exits)، لا على الوصول إلى الذاكرة. مع تفعيل EPT/NPT، تعمل القراءة والكتابة العاديتان داخل L2 بسرعة العتاد، بينما تتولى L0 الإدخال/الإخراج ومقاطعات المؤقت وMMIO والمقاطعات بين المعالجات (IPIs)، وقد تُعاد توجيهها عبر L1. العمل المرتبط بالمعالج على بيانات موجودة أصلًا في RAM يبدو قريبًا من الأداء الأصلي؛ أما أحمال العمل الثقيلة على استدعاءات النظام والحزم والقرص فتشعر بكل طبقة. استخدم أجهزة virtio في كل مكان وcache=none على أقراص الضيوف، ثم قِس حِمل عملك الخاص.

#nested-virtualization#kvm#proxmox#vps#qemu#libvirt