تشغيل wg-easy مع WireGuard عبر Docker وواجهة ويب
شغّل WireGuard عبر wg-easy وDocker Compose، مع المنافذ المطلوبة وNET_ADMIN وsysctl، وتعرّف على اختلاف الإصدار 15 ورموز QR للهواتف.
ما ستبنيه
wg-easy هو WireGuard مع واجهة ويب، ويعمل داخل حاوية Docker واحدة. يتولى إدارة واجهة WireGuard نيابةً عنك، ويضيف واجهة في المتصفح لإنشاء العملاء. يحصل كل عميل تنشئه على ملف إعداد ورمز QR، لذلك يمكن للهاتف الانضمام إلى VPN عبر توجيه الكاميرا إلى الشاشة.
النفق نفسه هو WireGuard عادي. تنقل وحدة kernel الحزم، لذلك تكون سرعة النقل مماثلة لإعداد مكتوب يدوياً. ما تحصل عليه هو إدارة دورة حياة العملاء: إضافة الـpeers وتعطيلها وحذفها دون تحرير ملف إعداد عبر SSH. وما تفقده هو التحكم المباشر في ذلك الملف، وهذا هو موضوع إعداد WireGuard يدوياً على VPS.
تحتاج إلى VPS من نوع KVM مع عنوان IPv4 عام، وDocker Engine مع Compose plugin، ووصول root. عادةً لا تستطيع تقنيات المحاكاة الافتراضية للحاويات التي تشارك kernel الخاص بالمضيف، مثل OpenVZ أو LXC، تحميل وحدة WireGuard، وستفشل الحاوية في تشغيل الواجهة.
نقلت Version 15 الإعدادات خارج البيئة
كُتبت معظم الأدلة التي ستجدها لـ wg-easy 14، حيث كنت تضبط WG_HOST على عنوان خادمك وPASSWORD_HASH على تجزئة bcrypt لكلمة مرور المسؤول، وكلاهما كان يُحدَّد كمتغيرات بيئية. أما Version 15 فهي إعادة كتابة. وتوضح ملاحظات الترحيل الرسمية صراحةً أن v15 لا تستخدم متغيرات البيئة نفسها التي تستخدمها v14، وأن معظم هذه الإعدادات نُقلت إلى لوحة المسؤول في واجهة الويب.
لذلك لم يعد WG_HOST وPASSWORD_HASH يؤديان أي وظيفة. إذا نسخت ملف compose قديماً، فستبدأ الحاوية وتتجاهل هذين السطرين، ثم تطلب منك إنشاء حساب مسؤول في المتصفح. هذا ليس خطأً. بل هو مسار الإعداد الجديد.
اعتباراً من July 2026، تكون العلامة الرئيسية التي ينبغي تثبيتها هي 15. ثبّت الإصدار الرئيسي بدلاً من استخدام latest، لأن ترقية الإصدار الرئيسي تغيّر تنسيق الإعدادات المخزّنة على القرص، ولن تتمكن من التراجع عنها بشكل سليم.
ملف 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، وهو volume مُسمّى، على مفتاح الخادم وكل عميل تنشئه. أنشئ نسخة احتياطية من هذا الـvolume، وإلا فستؤدي إعادة البناء إلى حذف جميع أقرانك. إذا كنت تفضّل رؤية هذه الملفات في نظام ملفات المضيف، فاستبدله بـbind mount. اقرأ الفرق بين bind mounts وvolumes المُسمّاة قبل ذلك، لأن الصلاحيات تختلف بينهما.
لماذا يحتاج إلى NET_ADMIN وSYS_MODULE وإعدادات sysctl
لا يُسمح للحاوية افتراضياً بالوصول إلى مكدس الشبكة، وكل سطر من هذه الأسطر يزيل عائقاً محدداً.
يتيح NET_ADMIN للحاوية إنشاء واجهة wg0، وإسناد عنوان إليها، وكتابة المسارات. ومن دونه تبدأ الحاوية ثم تتوقف أثناء تفعيل الواجهة، لأن ip link add wg0 type wireguard يعيد Operation not permitted.
يتيح SYS_MODULE، مع نقطة التحميل للقراءة فقط /lib/modules، للحاوية تحميل وحدة WireGuard من النواة إذا لم يكن المضيف قد حمّلها مسبقاً. توجد الوحدة في نواة المضيف، لا داخل الصورة، ولذلك يجب أن يكون مجلد المضيف مرئياً للحاوية. في النوى الحديثة تكون الوحدة مضمّنة عادةً، ويمكنك التأكد من ذلك باستخدام 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 على حاوية أُنشئت بإعدادات مختلفة يترك الشبكة في حالة غير متسقة. إذا أردت إعادة تشغيل الـ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 السبب.
إنشاء عميل ومسح رمزه على هاتف
في واجهة المستخدم، أنشئ عميلاً وامنحه اسماً ستتعرّف إليه لاحقاً، مثل اسم الجهاز الذي ينتمي إليه. يخصّص wg-easy عنوان النفق الحر التالي، وينشئ زوج المفاتيح نيابةً عنك. يوفّر كل صف من صفوف العملاء رمز QR وملف .conf قابلاً للتنزيل.
ثبّت تطبيق WireGuard الرسمي على الهاتف، واختر إضافة نفق من رمز QR، ثم وجّه الكاميرا إلى الرمز الظاهر على شاشتك. سيظهر النفق بالاسم الذي أدخلته. فعّله، وسيبدأ صف العميل في واجهة المستخدم بعرض عدادات النقل ووقت أحدث عملية handshake. بعد اتصال الهاتف بالنفق، يمكنه الوصول إلى خدمات لم تنشرها على الإنترنت، وهذا ما يتيح للهاتف مواصلة رفع الصور إلى خادم صور مستضاف ذاتياً من أي مكان، من دون أن يفتح ذلك الخادم منفذاً واحداً للعالم. وينطبق الأمر نفسه على الوسائط؛ إذ إن مكتبة Jellyfin أُعيد بناؤها كمتجر فيديو من تسعينيات القرن الماضي تكون مريحة للتصفح من غرفة فندق، مع بقائها خاصة كما كانت على شبكة LAN لديك. وتعمل التنبيهات في الاتجاه المعاكس عبر النفق نفسه، إذ يستطيع خادم ntfy مستضاف ذاتياً إرسال رسالة إلى ذلك الهاتف فور فشل مهمة نسخ احتياطي، من دون أن يستجيب قط لطلب من الإنترنت العام.
إذا لم يعرض العميل أي عملية handshake بعد تفعيله، فهذا يعني أنه لا يصل إلى الخادم إطلاقاً. ويشير ذلك إلى UDP 51820، إما في جدار الحماية لدى مزود الخدمة أو في عنوان endpoint المضمّن في الإعداد. أما العميل الذي يعرض عملية handshake لكن لا يوفّر اتصالاً عاملاً بالإنترنت، فيشير إلى مشكلة في إعادة التوجيه أو 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 فهو إعادة كتابة، وقد نقل المشروع upstream معظم إعداداته إلى لوحة الإدارة في واجهة الويب. لا يقرأ الحاوي أيّاً من المتغيرين، لذلك يبدأ بصورة طبيعية ثم يطلب منك إنشاء حساب مسؤول عند أول زيارة. عيّن عنوان المضيف الذي سيستخدمه العملاء في صفحة الإعداد تلك بدلاً من ذلك.
هل أحتاج إلى 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، داخل ملف wg0.json. تحتوي واجهة المستخدم أيضاً على زر للنسخ الاحتياطي يصدّر البيانات نفسها. انسخ هذا الملف إلى مكان خارج الخادم قبل إجراء أي ترقية. تتم الاستعادة بتحميل الملف أثناء خطوة الإعداد في حاوي جديد.
هل يمكنني تشغيل wg-easy خلف Reverse Proxy؟
نعم. ضع الـProxy أمام TCP 51821، وأنهِ TLS عنده، واضبط INSECURE=true على الحاوي حتى يقبل اتصال HTTP غير المشفّر القادم من الـProxy. اترك UDP 51820 منشوراً مباشرة، لأن حركة مرور VPN تستخدم UDP ولا تمر عبر HTTP Proxy.