SSD Nodes Learn Hosting plans →
الأدلة Matt Connorبقلم Matt Connor

تشغيل WireGuard بواجهة ويب عبر wg-easy وDocker

شغّل WireGuard خلف واجهة wg-easy باستخدام Docker Compose، مع المنافذ وNET_ADMIN وإعدادات sysctl المهمة، وأنشئ العملاء عبر رموز QR لهواتفك بسهولة.

ما الذي ستبنيه

wg-easy هو WireGuard مع واجهة ويب، ويعمل داخل حاوية Docker واحدة. يدير واجهة WireGuard نيابةً عنك، ويضيف واجهة في المتصفح لإنشاء العملاء. يحصل كل عميل تنشئه على ملف إعداد ورمز QR، لذلك ينضم الهاتف إلى VPN بتوجيه الكاميرا نحو الشاشة.

النفق نفسه هو WireGuard عادي. تنقل وحدة kernel الحزم، لذلك يكون معدل النقل مماثلاً لإعداد مكتوب يدوياً. ما تكسبه هو إدارة دورة حياة العملاء: إضافة النظراء وتعطيلهم وحذفهم دون تحرير ملف إعداد عبر SSH. وما تتخلى عنه هو التحكم المباشر في ذلك الملف، وهذا هو موضوع إعداد WireGuard اليدوي على VPS.

تحتاج إلى مضيف Linux يمكنك إدارته، مثل KVM VPS، مع عنوان IP عام أو اسم نطاق يشير إليه، ومعالج x86_64 أو arm64، وDocker Engine مع Compose plugin، ووصول root. عادةً لا تستطيع تقنيات المحاكاة الافتراضية للحاويات التي تشارك kernel المضيف، مثل OpenVZ أو LXC، تحميل وحدة WireGuard، وستفشل الحاوية في تشغيل الواجهة.

نقل الإصدار 15 الإعدادات خارج البيئة

كُتبت معظم الأدلة التي ستجدها لإصدار wg-easy 14، حيث كنت تضبط WG_HOST على عنوان خادمك وPASSWORD_HASH على تجزئة bcrypt لكلمة مرور المسؤول، وكان كلاهما متغيرَي بيئة. الإصدار 15 إعادة كتابة كاملة. توضح ملاحظات الترحيل الرسمية أن v15 لا يستخدم متغيرات البيئة نفسها التي يستخدمها v14، وأن معظم هذه المتغيرات نُقلت إلى لوحة المسؤول في واجهة الويب.

لذلك لم يعد WG_HOST وPASSWORD_HASH ينفذان أي إجراء. إذا نسخت ملف compose قديماً، فستبدأ الحاوية وتتجاهل هذين السطرين، ثم تطلب منك إنشاء حساب مسؤول في المتصفح. هذا ليس خللاً. بل هو مسار الإعداد الجديد.

اعتباراً من أكتوبر 2026، الوسم الرئيسي الذي يجب تثبيته هو 15. ثبّت الإصدار الرئيسي بدلاً من استخدام latest، لأن الترقية الرئيسية تغيّر تنسيق الإعدادات على القرص، ولن تتمكن من التراجع عنها بطريقة سليمة. أدى الانتقال إلى الإصدار 15 إلى استبدال ملف JSON في v14 بقاعدة بيانات SQLite.

ملف compose

أنشئ دليلاً للمكدس، واكتب ملف compose الرسمي فيه. هذا هو الملف المصدر، بعد حذف الأسطر الاختيارية التي كانت مسبوقة بعلامة تعليق.

sudo mkdir -p /etc/docker/containers/wg-easy
sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml \
  https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml

يبدو المحتوى كما يلي:

volumes:
  etc_wireguard:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:15
    container_name: wg-easy
    networks:
      wg:
        ipv4_address: 10.42.42.42
        ipv6_address: fdcc:ad94:bacf:61a3::2a
    volumes:
      - etc_wireguard:/etc/wireguard
      - /lib/modules:/lib/modules:ro
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv6.conf.all.disable_ipv6=0
      - net.ipv6.conf.all.forwarding=1
      - net.ipv6.conf.default.forwarding=1

networks:
  wg:
    driver: bridge
    enable_ipv6: true
    ipam:
      driver: default
      config:
        - subnet: 10.42.42.0/24
        - subnet: fdcc:ad94:bacf:61a3::/64

يمثل etc_wireguard وحدة تخزين مسماة تحتوي على مفتاح الخادم وكل عميل تنشئه، وتُخزَّن هذه البيانات في قاعدة بيانات SQLite المسماة wg-easy.db. أنشئ نسخة احتياطية من هذه الوحدة، وإلا فستؤدي إعادة البناء إلى حذف جميع نظرائك. إذا كنت تفضّل رؤية هذه الملفات على نظام ملفات المضيف، فاستبدلها بعملية bind mount، واقرأ الفرق بين bind mount ووحدات التخزين المسماة قبل ذلك، لأن الصلاحيات تختلف بينهما.

سبب الحاجة إلى NET_ADMIN وSYS_MODULE وsysctls

لا يُسمح للحاوية افتراضياً بالتعامل مع مكدس الشبكة، وكل سطر من هذه الأسطر يزيل عائقاً محدداً.

يسمح NET_ADMIN للحاوية بإنشاء واجهة wg0، وتعيين عنوان لها، وكتابة المسارات. من دونه تبدأ الحاوية ثم تتوقف أثناء تفعيل الواجهة، لأن ip link add wg0 type wireguard يعيد Operation not permitted.

يتيح SYS_MODULE، مع mount /lib/modules للقراءة فقط، للحاوية تحميل وحدة WireGuard في النواة إذا لم يكن المضيف قد حمّلها مسبقاً. توجد الوحدة في نواة المضيف، وليس داخل image، ولذلك يجب أن يكون دليل المضيف مرئياً. في النوى الحديثة تكون الوحدة مضمّنة عادةً، ويمكنك التحقق من ذلك باستخدام sudo modprobe wireguard && echo ok على المضيف.

يجعل net.ipv4.ip_forward=1 النواة تعيد توجيه الحزم التي لا تكون موجهة إلى الجهاز نفسه. من دونه يتصل العميل، وتنجح المصافحة، ثم تُسقط كل حزمة متجهة إلى الإنترنت، ولذلك تنتهي مهلة ping 1.1.1.1 بينما تبدو VPN متصلة.

يُفاجئ net.ipv4.conf.all.src_valid_mark=1 بعض المستخدمين. يعلّم WireGuard حزم الخرج الخاصة به حتى لا تُوجَّه مجدداً إلى النفق. يرى ترشيح المسار العكسي الصارم حزمةً لا يطابق عنوان مصدرها المسار المتوقع، فيسقطها. يخبر هذا sysctl النواة بقبول الحزم المعلّمة، وهذا ما يمنع النفق الكامل من تعطيل نفسه.

شغّل الخدمة وأنشئ حساب المسؤول

cd /etc/docker/containers/wg-easy
sudo docker compose up -d
sudo docker compose logs -f

استخدم docker compose up وdocker compose down، وليس start وstop. يعيد start تشغيل الحاويات الموجودة مسبقاً فقط، لذلك لا يُطبّق أي تغيير أجريته على ملف compose، بما في ذلك إعدادات الشبكة وsysctl، بينما يعيد up إنشاء كل ما تغيّر. إذا أردت استعادة الـstack بعد إعادة التشغيل، فإن restart: unless-stopped يتكفّل بذلك، وتشرح آلية إقلاع خدمات compose ما تضمنه هذه السياسة وما لا تضمنه.

تستمع واجهة الويب على TCP 51821. عند زيارتها أول مرة، تعرض صفحة إعداد تنشئ فيها حساب المسؤول وتؤكد عنوان المضيف الذي سيستخدمه العملاء للوصول إلى الخادم. يظهر عنوان المضيف هذا في سطر Endpoint ضمن إعدادات كل عميل، لذلك يجب أن يكون عنوان IP العام أو اسم DNS الخاص بـVPS. إذا كان العنوان خاطئاً، فسيشير رمز QR الذي تسلّمه للهاتف إلى وجهة يتعذر الوصول إليها، ولن تكتمل المصافحة.

هناك أمر آخر يتعلق بهذا المنفذ: يرفض wg-easy 15 استخدام HTTP العادي ما لم تضبط INSECURE=true. لا توجد مشكلة في الوصول إليه عبر HTTPS باستخدام شهادة غير موثوقة، أو في إنهاء TLS عبر reverse proxy أمامه. أما الوصول إليه عبر http:// باستخدام الإعدادات الافتراضية، فغير مسموح.

لا تنشر منفذ واجهة المستخدم على الإنترنت

ينشر ملف Compose المنفذ 51821 على جميع الواجهات. هذه صفحة تسجيل دخول إلى جهاز يمكنه توجيه حركة الشبكة الخاصة بك، لذلك يجب ألا يكون المنفذ مفتوحاً للعالم. يؤدي نشر منفذ في Docker إلى كتابة قواعد في سلسلة DOCKER، التي تُقيَّم قبل ufw؛ لذلك لا تغلق قاعدة ufw deny هذا المنفذ. من المهم فهم هذا الفخ بشكل مستقل، ويشرح سبب تجاهل المنافذ التي ينشرها Docker لقواعد ufw هذه المسألة بالكامل.

الحل البسيط هو ربط واجهة المستخدم بواجهة loopback والوصول إليها عبر نفق SSH:

    ports:
      - "51820:51820/udp"
      - "127.0.0.1:51821:51821/tcp"
    environment:
      - INSECURE=true

ثم نفّذ الأمر التالي من جهازك المحمول:

ssh -L 51821:127.0.0.1:51821 youruser@your.server.address

افتح http://127.0.0.1:51821 في المتصفح على جهازك المحمول. يشفّر SSH حركة الشبكة، ولا يستجيب المنفذ لأي طرف آخر، ويكون INSECURE=true آمناً هنا لأن قفزة HTTP غير المشفرة لا تغادر واجهة loopback.

افتح UDP 51820 وتحقق من كلا الجدارين الناريين

يحتاج WireGuard نفسه إلى إمكانية الوصول إلى UDP 51820 من الإنترنت. ينشره Docker، لكن العديد من مزوّدي الخدمة يضعون جداراً نارياً منفصلاً للشبكة أمام VPS، ولا يعرف Docker شيئاً عنه. افتح المنفذ في الموضعين. إذا كنت تدير جدار المضيف الناري باستخدام ufw، فإن قواعد ufw الأساسية لـVPS تمثل المسار الأقصر مقارنة بكتابة قواعد nftables يدوياً.

تحقق من أن الحاوية تستمع فعلياً:

sudo ss -ulnp | grep 51820

يُفترض أن ترى مأخذ UDP في حالة الاستماع. عدم ظهور أي شيء في ذلك السطر يعني أن الحاوية لم ترفع الواجهة، وسيحدد sudo docker compose logs wg-easy السبب.

إنشاء عميل ومسح رمز QR بهاتف

أنشئ عميلاً في واجهة المستخدم، وامنحه اسماً يمكنك تمييزه لاحقاً، مثل اسم الجهاز الذي ينتمي إليه. يخصّص wg-easy عنوان النفق الحر التالي، وينشئ زوج المفاتيح نيابةً عنك. يعرض كل صف من صفوف العملاء رمز QR وملف .conf قابلاً للتنزيل.

ثبّت تطبيق WireGuard الرسمي على الهاتف، واختر إضافة نفق من رمز QR، ثم وجّه الكاميرا إلى الرمز الظاهر على شاشتك. سيظهر النفق بالاسم الذي أدخلته. فعّله، وسيبدأ صف العميل في واجهة المستخدم بعرض عدادات النقل ووقت أحدث مصافحة. عندما يتصل الهاتف بالنفق، يمكنه الوصول إلى الخدمات التي لم تنشرها على الإنترنت، وبذلك يواصل الهاتف رفع الصور إلى خادم صور مستضاف ذاتياً من أي مكان، من دون أن يكون لدى ذلك الخادم منفذ واحد مفتوح للعالم. وتنطبق الطريقة نفسها على الوسائط؛ إذ تصبح مكتبة Jellyfin أُعيد بناؤها كمتجر فيديو من التسعينيات ممتعة للتصفح من غرفة فندق، مع بقائها خاصة كما كانت على شبكة LAN لديك. وتعمل التنبيهات في الاتجاه المعاكس عبر النفق نفسه، إذ يمكن لـخادم ntfy مستضاف ذاتياً إرسال رسالة إلى ذلك الهاتف لحظة فشل مهمة نسخ احتياطي، من دون أن يستجيب أبداً لطلب من الإنترنت العام.

إذا لم يعرض العميل أي مصافحة بعد تفعيله، فهذا يعني أنه لا يصل إلى الخادم إطلاقاً. يشير ذلك إلى UDP 51820، إما في جدار الحماية لدى موفر الخدمة، أو في عنوان endpoint المضمّن في ملف الإعداد. أما العميل الذي يعرض مصافحة، لكن لا يوفّر اتصالاً فعلياً بالإنترنت، فيشير إلى مشكلة في إعادة التوجيه أو DNS.

على جهاز سطح المكتب، نزّل ملف .conf واستورده إلى عميل WireGuard بدلاً من إعادة كتابته يدوياً. يُنشأ المفتاح الخاص في هذا الملف مرة واحدة، ويُعرض مرة واحدة. تعامل مع الملف كما تتعامل مع مفتاح SSH الخاص.

متى تتجاوز واجهة المستخدم

يكون wg-easy الأداة المناسبة ما دام نظراؤك أشخاصاً وهواتف. الواجهة أسرع من تحرير ملفات الإعداد، وإبطال هاتف مفقود لا يتطلب سوى نقرة واحدة.

ستصل إلى حدودها عندما تريد شيئاً لا تمثله الواجهة. يُعد التوجيه من موقع إلى موقع، حيث يغطي AllowedIPs الخاص بأحد النظراء شبكة فرعية بعيدة كاملة بدلاً من عنوان واحد، أول عائق شائع. وتأتي بعده الأنفاق المنقسمة مع قواعد توجيه لكل نظير، أو إعداد ينشئه أداة التزويد لديك. عندئذٍ لا يكون الإعداد المكتوب يدوياً أصعب، بل مختلفاً فقط، ويوضح دليل WireGuard العادي إنشاء النفق نفسه من wg0.conf. وإذا كنت تفضل إيقاف تشغيل طبقة التحكم بالكامل، فاستعرض مقارنة WireGuard مع Tailscale الخيار المُدار. يعتمد كون ذلك تبادلاً عادلاً على ما يمكن لخادم التنسيق الوصول إليه فعلياً، ويستحق نموذج الثقة في Tailscale القراءة قبل منحه إمكانية الوصول إلى شبكتك. تكون التكلفة عادةً السؤال التالي، وتغطي التغطية الفعلية للخطة المجانية في Tailscale ما يصل إلى ستة مستخدمين دون تكلفة، وللاستخدام غير التجاري فقط، لذلك لا تدفع الأسرة شيئاً بينما لا يتأهل فريق شركة صغيرة مهما قل عدد أفراده. بعد ذلك، تحسب الفوترة المستخدمين بدلاً من الأجهزة، وهذا يختلف عن تكلفة VPS التي تدفعها مسبقاً، لذلك تحقّق من تكلفة Tailscale بعد تجاوز الخطة المجانية قبل نقل فريقك. للنفق الكامل الذي أنشأته للتو مكافئ مباشر هناك، إذ يتيح الإعلان عن VPS بوصفه عقدة خروج في Tailscale استخدام المسار نفسه عبر الخادم، مع اعتماد ذلك في وحدة تحكم الإدارة بدلاً من كتابته في إعداد كل عميل. ولحاجز الشبكة الفرعية مكافئ أيضاً، لأن الإعلان عن شبكة خاصة كاملة من VPS يتيح تلك الشبكة لكل جهاز في tailnet دون تحرير AllowedIPs لكل نظير، وهو التحرير الذي دفعك إلى تجاوز الواجهة. وإذا كنت تريد لوحة المعلومات والتوجيه الشبكي التلقائي، لكنك لا تريد خادم تنسيق مملوكاً لجهة أخرى، فإن تشغيل خادم NetBird الخاص بك على VPS يبقي طبقة التحكم على أجهزة تملكها، مقابل إعداد DNS وTLS الذي لم يطلبه منك wg-easy.

إذا كان تركيب Compose المذكور أعلاه هو الجزء غير المألوف، وليس WireGuard، فإن أساسيات Docker Compose على VPS يشرح تنسيق الملف والأوامر اليومية.

FAQ

لماذا يتجاهل wg-easy المتغيرين WG_HOST وPASSWORD_HASH؟

ينتمي هذان المتغيران إلى wg-easy 14. أما الإصدار 15 فهو إعادة كتابة، وقد نقل المشروع الأساسي معظم إعداداته إلى لوحة الإدارة في واجهة الويب. لا يقرأ الحاوي أيّاً من المتغيرين، لذلك يبدأ بشكل طبيعي ثم يطلب منك إنشاء حساب مسؤول عند أول زيارة. حدّد عنوان المضيف الذي سيستخدمه العملاء في صفحة الإعداد تلك بدلاً من ذلك.

هل أحتاج إلى SYS_MODULE إذا كانت النواة تتضمن WireGuard بالفعل؟

لا. يوجد SYS_MODULE وعمليات الربط /lib/modules حتى يتمكن الحاوي من تحميل الوحدة عندما لا تكون متاحة على المضيف. على مضيف ينجح فيه sudo modprobe wireguard مسبقاً، لا تُستخدم هذه الإمكانية. وإزالتها خطوة مناسبة لتقوية الأمان، بينما يظل NET_ADMIN مطلوباً في كلتا الحالتين.

يتصل العميل، لكن لا يوجد إنترنت. ما المشكلة؟

تعني المصافحة من دون حركة مرور، في معظم الحالات، وجود مشكلة في إعادة التوجيه. تأكد من بقاء net.ipv4.ip_forward=1 وnet.ipv4.conf.all.src_valid_mark=1 في ملف compose، لأن النسخة المعدّلة يدوياً تفقدهما كثيراً. إذا كان إعادة التوجيه مفعّلاً، فتحقق من خادم DNS الذي تلقّاه العميل. تبدو النفق الذي يرسل كل حركة المرور عبر VPN، لكنه يشير إلى خادم DNS لم يعد قادراً على الوصول إليه، كأنه اتصال متوقف في المتصفح.

كيف أنشئ نسخة احتياطية من عملائي؟

توجد كل البيانات في وحدة التخزين المسماة etc_wireguard. في الإصدار 15، يعني ذلك وجود قاعدة بيانات SQLite في /etc/wireguard/wg-easy.db داخل الحاوي. لا تذكر وثائق الإصدار v15 ميزة للنسخ الاحتياطي أو التصدير، لذلك أنشئ نسخة احتياطية من وحدة التخزين نفسها: شغّل docker compose down، وانسخ محتويات وحدة التخزين إلى مكان خارج الخادم، ثم شغّل المكدس مجدداً باستخدام docker compose up -d. نفّذ ذلك قبل أي ترقية. ينتمي الملف wg0.json الذي تذكره الأدلة الأقدم إلى wg-easy 14. وهو الملف الذي يصدّره زر النسخ الاحتياطي في الإصدار v14، أما في الإصدار v15 فالاستخدام الوحيد له هو رفعه في معالج الإعداد عند ترحيل تثبيت قديم.

هل يمكنني تشغيل wg-easy خلف Reverse Proxy؟

نعم. ضع الـProxy أمام TCP 51821، وأنهِ TLS هناك، واضبط INSECURE=true على الحاوي حتى يقبل قفزة HTTP العادية من الـProxy. اترك UDP 51820 منشوراً مباشرة، لأن حركة مرور VPN تستخدم UDP ولا تمر عبر HTTP Proxy.