الأدلة التقنية

شبكة خاصة مع WireGuard وواجهة wg-easy

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

شبكة خاصة مع WireGuard وواجهة wg-easy

لنفرض أن لديك سيرفراً تشغل عليه Portainer ولوحة ال Reverse Proxy وواجهة مراقبة Monitoring Dashboard وقاعدة بيانات Database، فالطريقة الأسهل التي يبدأ بها الكثيرون هي أن ينشر كل لوحة منها على منفذ Port أو نطاق فرعي Subdomain يفتح من أي مكان ثم يحميها بكلمة مرور، والمشكلة أن كل لوحة تنشرها على الإنترنت هي باب إضافي عليك أن تحرسه وتحدثه وتراقب من يطرقه، مع أن أحداً من خارج فريقك لا يحتاج أن يرى هذه الأدوات أصلاً.

وقد يتساءل البعض: أليست كلمة المرور القوية كافية؟ والإجابة أن كلمة المرور تحميك من التخمين، ولكنها لا تحميك من ثغرة في اللوحة نفسها ولا من إعداد خاطئ يتركها دون مصادقة Authentication، لذلك فالحل الأنسب هو أن تضع هذه الأدوات داخل شبكة خاصة افتراضية VPN، حيث يتصل جهازك بالسيرفر Server عبر نفق Tunnel مشفر فيصبح جزءاً من الشبكة الداخلية Internal Network، وتبقى تلك الخدمات مغلقة أمام العالم فلا يراها إلا من يملك مفتاحاً.

وWireGuard هو بروتوكول VPN حديث مدمج في نواة Linux، أي ال Kernel، وكوده صغير يمكن مراجعته، وخوارزميات التشفير فيه Encryption Algorithms حديثة وثابتة، فلا توجد خيارات قد تخطئ في ضبطها، وأداؤه يتفوق بفارق كبير على OpenVPN وIPsec. وصعوبته الوحيدة في الإدارة، حيث يحتاج كل جهاز إلى مفتاح Key وعنوان وملف إعداد Config File خاص به، وتوزيع هذه الملفات يدوياً على فريق كامل يصبح مرهقاً بسرعة.

وهذه الصعوبة يحلها wg-easy، وهو Container واحد يشغل WireGuard ويضيف إليه واجهة ويب Web UI، تنشئ منها العملاء Clients وتعرض لكل عميل رمز QR يقرؤه تطبيق الهاتف، وتوقف أي جهاز أو تفعله بنقرة، وترى من اتصل ومتى. وwg-easy مناسب للفريق الصغير أو المختبر المنزلي Homelab، أما إذا كان لديك مئات الأجهزة وتحتاج إلى ربطها بدليل المستخدمين User Directory وإلى سياسات وصول Access Policies دقيقة، فانظر في حلول ال Overlay Network مثل Headscale أو NetBird.

وسوف نناقش في هذا المقال ما يلي:

  • كيف يعمل WireGuard بالعناوين، والفرق بين النفق الكامل Full Tunnel والنفق الجزئي Split Tunnel.
  • تثبيت wg-easy بملف Compose لا ينشر واجهة الإدارة على الإنترنت، ولماذا نغير الملف الرسمي في هذه النقطة بالذات.
  • الوصول إلى الواجهة عبر HTTPS أو عبر نفق SSH، ثم إضافة الأجهزة وعزل العملاء عن بعضهم.
  • التحقق من النجاح، والنسخ الاحتياطي، والتحديث، وأشهر المشكلات وحلولها.

المتطلبات Requirements

  • سيرفر Linux بعنوان IP عام عليه Docker وCompose (انظر تثبيت Docker على Ubuntu)، ولاحظ أن نواة Linux 5.6 وما بعدها تتضمن WireGuard مدمجاً، وUbuntu 24.04 يستوفي هذا الشرط.
  • موارد قليلة جداً، حيث يستهلك ال Container قرابة 65 ميجابايت من الذاكرة RAM.
  • منفذ UDP واحد مفتوح من الإنترنت، وهو افتراضياً 51820/udp، والسبب أن WireGuard لا يعمل عبر TCP كما تذكر صفحة القيود المعروفة في موقع المشروع.
  • نطاق فرعي يشير إلى السيرفر، مثل vpn.example.com للنفق، وwg.example.com للواجهة إذا أردت الوصول إليها عبر ال Reverse Proxy.
  • تطبيق WireGuard الرسمي على الأجهزة، وهو متوفر لـ Windows وmacOS وLinux وAndroid وiOS.
💡
إذا كان السيرفر في منزلك خلف CGNAT، فلن يصل إليه أحد عبر منفذ UDP وارد، لذلك اقرأ أولاً دليل تشغيل خادمك من إنترنت المنزل، والحل المعتاد أن تضع wg-easy على VPS صغير يتصل به الجميع، ومنهم سيرفر المنزل نفسه.

كيف يوزع WireGuard العناوين، ومتى تختار النفق الكامل Full Tunnel أو الجزئي Split Tunnel

ينشئ wg-easy واجهة شبكة Interface اسمها wg0 لشبكة خاصة هي افتراضياً 10.8.0.0/24، حيث يأخذ السيرفر العنوان 10.8.0.1 ويأخذ كل عميل العنوان الذي يليه (10.8.0.2، 10.8.0.3...). وأهم حقل في إعداد العميل هو AllowedIPs، والسبب أنه يحدد الحركة Traffic التي يرسلها الجهاز عبر النفق، وبالتالي يحدد نوع النفق كما في الجدول التالي:

نفق كامل (full tunnel)نفق جزئي (split tunnel)
AllowedIPs0.0.0.0/0, ::/0شبكات محددة، مثل 10.8.0.0/24, 10.0.10.0/24
ما يمر عبر النفقحركة الجهاز كلها، ويخرجها السيرفر إلى الإنترنتالحركة المتجهة إلى الشبكات الداخلية وحدها، والباقي يخرج من اتصال الجهاز مباشرة
متى تختارهفي شبكات Wi-Fi العامة غير الموثوقة، أو عندما تريد أن يظهر الجهاز بعنوان السيرفرللوصول إلى الأدوات الداخلية دون أن يبطؤ تصفح الموظف، ودون أن يحمل السيرفر حركته
التكلفةتصفح الفريق كله يمر عبر السيرفر ويستهلك من ال Bandwidthحركة أقل وتأخير Latency أقل

والنفق الكامل هو الإعداد الافتراضي في wg-easy، وتستطيع تغييره للجميع من لوحة الإدارة Admin Panel، أو لعميل واحد كما سيأتي.

التثبيت Installation

نبدأ بإنشاء مجلد الخدمة:

sudo mkdir -p /opt/wg-easy
sudo chown $USER: /opt/wg-easy
cd /opt/wg-easy

الملف الرسمي في مستودع المشروع ينشر منفذ الواجهة 51821/tcp على جميع عناوين السيرفر، وهذا مناسب لشبكة منزلية خلف Router، ولكنه على VPS بعنوان عام يعني أن صفحة الدخول إلى لوحة تتحكم في شبكتك كلها مفتوحة لكل من يمسح المنافذ، وتذكر أن Docker ينشر هذا المنفذ متجاوزاً ufw كما سيأتي. لذلك بنينا الملف التالي /opt/wg-easy/compose.yaml على الملف الرسمي في التوثيق مع ثلاثة تغييرات: لا ننشر فيه إلا منفذ النفق، ونثبت فيه رقم الإصدار Version Pinning، ونصله بشبكة ال Reverse Proxy:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:15.4.0
    container_name: wg-easy
    restart: unless-stopped
    environment:
      PORT: 51821
      HOST: 0.0.0.0
    networks:
      wg:
        ipv4_address: 10.42.42.42
        ipv6_address: fdcc:ad94:bacf:61a3::2a
        interface_name: eth0
        gw_priority: 1
      proxy:
        interface_name: eth1
    volumes:
      - etc_wireguard:/etc/wireguard
      - /lib/modules:/lib/modules:ro
    ports:
      - "51820:51820/udp"
    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

volumes:
  etc_wireguard:
    name: etc_wireguard

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

في الإعداد أعلاه لاحظ التالي:

  • المنفذ UDP هو الوحيد المنشور. الواجهة تعمل على 51821/tcp داخل ال Container ولا ننشرها على السيرفر، وإنما يصل إليها ال Reverse Proxy عبر شبكة proxy المشتركة، وإذا لم تكن موجودة فأنشئها بالأمر docker network create proxy، وإذا لم يكن لديك Reverse Proxy بعد فانظر قسم «كيف تفتح واجهة الإدارة بأمان» أدناه.
  • السطران interface_name وgw_priority ليسا للزينة. يكتب wg-easy قاعدة ترجمة العناوين NAT من نوع MASQUERADE على الواجهة eth0 افتراضياً، وعندما يتصل ال Container بشبكتين فقد يعطي Docker الاسم eth0 لشبكة proxy ويجعل المخرج الافتراضي Default Gateway عبر الشبكة الأخرى، وبالتالي تنجح المصافحة Handshake ويصل العميل إلى 10.8.0.1 ولكن الإنترنت لا يعمل في النفق الكامل. لذلك نثبت اسم الواجهة لكل شبكة بخيار interface_name، ونجعل شبكة wg هي المخرج الافتراضي بخيار gw_priority.
  • الصلاحية Capability NET_ADMIN تسمح لل Container بإنشاء الواجهة wg0 وقواعد iptables، والصلاحية SYS_MODULE مع تركيب Mount المجلد /lib/modules تسمح له بتحميل وحدة النواة Kernel Module الخاصة بـ WireGuard إن لم تكن النواة قد حملتها.
  • الإعداد ip_forward يسمح لل Container بتمرير Forwarding حركة العملاء إلى الشبكة والإنترنت، وهذه القيم تسري داخل ال Container وحده ولا تغير إعدادات السيرفر.
  • الحالة State كلها محفوظة في ال Volume etc_wireguard: قاعدة SQLite فيها العملاء والمفاتيح، والملف wg0.conf.
  • إذا لم يكن IPv6 مفعلاً في Docker على سيرفرك، فاحذف أسطر IPv6 من الشبكة ومن sysctls، وأضف DISABLE_IPV6: "true" إلى environment كما في توثيق الإعدادات الاختيارية، وأبق السطر gw_priority في مكانه، والسبب أن Docker عندما يجد شبكتين بنفس الأولوية يختار المخرج بنفسه، وقد يختار شبكة proxy.

افتح المنفذ UDP في جدار الحماية Firewall على السيرفر، وفي جدار المزود إن وجد، ولكن تذكر أن المنافذ التي ينشرها Docker تتجاوز ufw، أي أن المنفذ سوف يكون مفتوحاً حتى دون هذه القاعدة Rule، ومع ذلك أضفها حتى يبقى ما تقصده موثقاً في إعداد الجدار، أما جدار المزود فيعمل خارج السيرفر ولا يتأثر بـ Docker، فإذا كان يمنع الوارد افتراضياً فلا بد أن تفتح فيه 51820/udp:

sudo ufw allow 51820/udp

الآن سوف نشغل الخدمة ونتابع السجلات Logs حتى نرى أن الواجهة بدأت العمل:

docker compose up -d
docker compose logs --tail 20 wg-easy

والمخرج سوف يكون كما يلي، بعد حذف التوقيت من بداية كل سطر:

WireGuard Config synced successfully.
WireGuard Wireguard Interface wg0 started successfully.
WireGuard Applying firewall rules...
WireGuard Firewall rules applied successfully.
⚠️
يوصي توثيق wg-easy صراحة بإيقاف الخدمة وتشغيلها بالأمرين docker compose down وdocker compose up -d وليس بالأمرين stop وstart، والسبب أن الواجهة وقواعد الشبكة قد تبقى في حالة غير متسقة فيفشل التشغيل التالي.

كيف تفتح واجهة الإدارة Web UI بأمان

الواجهة في الإصدار 15 ترفض افتراضياً العمل عبر HTTP غير المشفر، والسبب أن كلمة مرور المدير تمر من خلالها، وكذلك ملفات الإعداد التي تحمل المفاتيح الخاصة Private Keys للعملاء، والحل الذي يلجأ إليه البعض هو تفعيل INSECURE مع نشر المنفذ على العنوان العام، وهذا الحل غير مناسب إطلاقاً لأنه يعرض كلمة المرور والمفاتيح لكل من يمر في الطريق بينك وبين السيرفر. لذلك أمامك طريقان صحيحان:

  1. عبر Reverse Proxy بـ HTTPS (الطريق الموصى به): أنشئ في Nginx Proxy Manager Proxy Host للنطاق wg.example.com يوجه إلى http://wg-easy:51821، وفعل عليه شهادة Let's Encrypt وخيار Force SSL، ثم أضف قائمة وصول Access List تقصر الواجهة على عناوين الفريق، حتى لا تبقى صفحة الدخول مفتوحة لكل من يعرف النطاق.
  2. عبر نفق SSH دون نطاق: انشر الواجهة على العنوان 127.0.0.1 وحده بإضافة - "127.0.0.1:51821:51821/tcp" إلى ports، ثم أضف المتغير INSECURE: "true" كما في دليل التشغيل دون Reverse Proxy، وبعدها نفذ من جهازك ssh -L 51821:127.0.0.1:51821 [email protected] وافتح http://localhost:51821، وهنا تمر الحركة مشفرة داخل SSH. ولا تستخدم INSECURE أبداً مع منفذ منشور على عنوان عام، والسبب ما ذكرناه أعلاه.
📌
في فبراير 2018 نشرت شركة RedLock أن لوحة إدارة Kubernetes تابعة لشركة Tesla كانت مكشوفة للإنترنت دون كلمة مرور، فدخلها المهاجمون وشغلوا عليها برامج تعدين عملات رقمية Cryptomining أخفوا حركتها خلف Cloudflare، ووجدوا داخل أحد ال Pods بيانات دخول إلى بيئة AWS أوسع فيها S3 Bucket يحمل بيانات قياس Telemetry للسيارات. والدرس أن لوحة الإدارة التي لا يحتاجها إلا فريقك لا مكان لها على العنوان العام، فإذا كانت خلف VPN فلن يجدها من يمسح الإنترنت أصلاً.

معالج الإعداد الأول Setup Wizard

أول مرة تفتح فيها الواجهة يظهر معالج من خطوات قصيرة، وبعد صفحة الترحيب تنشئ حساب المدير باسم مستخدم وكلمة مرور قوية:

خطوة إنشاء حساب المدير في معالج إعداد wg-easy
إنشاء حساب المدير

بعد ذلك يسألك المعالج إذا كان لديك إعداد سابق تريد استيراده، من wg-easy 14 مثلاً، وفي التثبيت الجديد اختر No.

الخطوة الأهم هي حقلا Host وPort، والسبب أن wg-easy يكتب قيمتيهما في حقل Endpoint داخل ملف كل عميل، لذلك اكتب النطاق vpn.example.com وليس عنوان IP، فإذا نقلت السيرفر لاحقاً كفاك تغيير سجل DNS ولن تحتاج لإعادة توزيع الإعدادات. والمنفذ هو الذي يصل إليه العملاء من الإنترنت (51820)، ويستمع عليه WireGuard داخل ال Container أيضاً، فإذا غيرته هنا فغير سطر ports إلى القيمة نفسها.

خطوة إدخال Host وPort في معالج wg-easy
العنوان والمنفذ اللذان يتصل بهما العملاء

وإذا كنت تنشر الخدمة آلياً Automated Deployment بأداة مثل Ansible، فتستطيع تخطي المعالج بـ متغيرات الإعداد التلقائي Unattended Setup INIT_ENABLED وINIT_USERNAME وINIT_PASSWORD وINIT_HOST وINIT_PORT، وwg-easy يقرأ هذه المتغيرات في التشغيل الأول فقط، لذلك احذفها بعده حتى لا تبقى كلمة المرور مكتوبة في ملف Compose.

إضافة الأجهزة Clients

من الصفحة الرئيسية اضغط New، واكتب اسماً يدل على الشخص والجهاز معاً (laptop-ahmad، phone-sara)، وللحسابات المؤقتة مثل حسابات المتعاقدين تستطيع تحديد تاريخ انتهاء Expiration Date يوقف بعده wg-easy العميل تلقائياً.

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

قائمة العملاء في wg-easy مع العناوين وأزرار التعديل وQR والتنزيل والرابط
لكل عميل: تفعيل أو إيقاف، وتعديل، ورمز QR، وتنزيل الملف، ورابط لمرة واحدة

وتوصل الإعداد إلى الجهاز بإحدى ثلاث طرق:

  • رمز QR: للهواتف، حيث تختار في تطبيق WireGuard إضافة نفق ثم مسح رمز QR.
  • تنزيل الملف: ملف .conf للحواسيب، تستورده في التطبيق من خيار Import tunnel from file.
  • الرابط لمرة واحدة One-Time Link: يرسل المدير رابطاً قصيراً إلى الموظف فينزل منه الإعداد مرة واحدة ثم يبطل الرابط، وإذا لم يستخدمه تنتهي صلاحيته بعد 5 دقائق، وهذا أفضل من إرسال الملف نفسه بالبريد أو في محادثة يبقى فيها للأبد.
نافذة رمز QR لعميل في wg-easy مع أزرار نسخ وتنزيل PNG (الرمز مموه)
نافذة رمز QR. موهنا الرمز في الصورة لأنه يحمل المفتاح الخاص للعميل

والمثال التالي يبين ملف عميل كما تولده الواجهة، بعد اختصار المفاتيح:

[Interface]
PrivateKey = CKTp...XHE4=
Address = 10.8.0.2/32, fdcc:ad94:bacf:61a4::cafe:2/128
MTU = 1420
DNS = 1.1.1.1, 2606:4700:4700::1111

[Peer]
PublicKey = yErX...eG4=
PresharedKey = 7zO3...CZ0M=
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 0
Endpoint = vpn.example.com:51820

في الإعداد أعلاه لاحظ التالي:

  • القسم [Interface] يخص الجهاز نفسه: مفتاحه الخاص وعنوانه داخل النفق وخوادم DNS التي يستخدمها أثناء الاتصال.
  • القسم [Peer] يخص السيرفر: مفتاحه العام، ومفتاح مشترك إضافي PresharedKey يولده wg-easy لكل عميل، وعنوان الاتصال Endpoint الذي كتبته في المعالج.
  • القيمة AllowedIPs = 0.0.0.0/0, ::/0 تعني نفقاً كاملاً، والقيمة PersistentKeepalive = 0 تعني أن الجهاز لا يرسل حزماً دورية Keepalive للإبقاء على الاتصال.
🛑
يحمل ملف الإعداد ورمز QR قيمة PrivateKey، ومن يحصل عليهما يدخل شبكتك باسم ذلك الجهاز، لذلك عاملهما معاملة كلمة المرور: لا تلتقط لهما صوراً، ولا ترسلهما عبر قنوات عامة، واحذف الملف من مجلد التنزيلات بعد استيراده. وإذا فقد أحد الموظفين جهازه أو غادر المؤسسة، فأوقف عميله أو احذفه من الواجهة فوراً.

نفق جزئي لعميل واحد أو للجميع

لتغيير الإعداد الافتراضي للجميع افتح Admin Panel ثم Config، وعدل حقلي Allowed IPs وDNS، ولاحظ أن هذه القيم تدخل في ملفات العملاء الجدد فقط، أما العملاء الحاليون فيحتاجون إلى تنزيل ملفاتهم من جديد. وإذا كان لديك DNS داخلي، مثل AdGuard Home على 10.8.0.1، فضعه هنا مكان خوادم DNS العامة.

صفحة Config في لوحة إدارة wg-easy مع Host وPort وAllowed IPs وDNS
الإعداد العام للعملاء: النفق الكامل هو الافتراضي

ولعميل واحد افتح صفحته من زر التعديل، وضع في Allowed IPs الشبكات التي يحتاجها فقط، وفي مثالنا هما شبكة VPN نفسها وشبكة داخلية 10.0.10.0/24 خلف السيرفر، ثم اضبط في قسم Advanced قيمة Persistent Keepalive على 25 للأجهزة التي تعمل خلف NAT، وهي غالباً الهواتف، والسبب أن ال Router يسقط جلسة UDP عندما تخلو من الحركة.

صفحة تعديل عميل في wg-easy مع Allowed IPs مخصصة لشبكتين
عميل بنفق جزئي: شبكتان فقط تمران عبر VPN

وبعد الحفظ سوف تجد أن ملف هذا العميل يتضمن:

AllowedIPs = 10.8.0.0/24, 10.0.10.0/24
PersistentKeepalive = 25

تذكر أن AllowedIPs في ملف العميل يحدد ما يرسله الجهاز عبر النفق فقط، والمستخدم يستطيع تعديله على جهازه متى شاء، لذلك فهو إعداد للتوجيه Routing وليس قيداً أمنياً، وإذا أردت أن تمنع العميل فعلاً من الوصول إلى شبكة ما فاستخدم الجدار الناري لكل عميل في القسم التالي، كما يوضح توثيق إعدادات العميل.

أما الحقل Server Allowed IPs فيعمل في الاتجاه المعاكس، حيث يحدد الشبكات الواقعة خلف العميل التي يريد السيرفر الوصول إليها، ومثال ذلك عميل هو Router في فرع للشركة يصل شبكة الفرع كلها بالسيرفر.

عزل العملاء Isolation

افتراضياً يصل كل عميل إلى كل ما خلف السيرفر وإلى العملاء الآخرين أيضاً، ولتغيير ذلك افتح Admin Panel ثم Interface، وفعل خيار Enable Per-Client Firewall، وعندها يظهر في صفحة كل عميل حقل Firewall Allowed IPs تكتب فيه الوجهات المسموح بها وحدها، ويطبقه wg-easy على السيرفر بقواعد iptables فلا يستطيع العميل تجاوزه من جهازه. وبهذا الشكل يصل المتعاقد مثلاً إلى سيرفر واحد أو منفذ واحد وليس إلى الشبكة كلها، ومن الصفحة نفسها تغير المنفذ ونطاق العناوين (Change CIDR).

صفحة Interface في لوحة إدارة wg-easy مع MTU وPort وDevice وخيار Per-Client Firewall
إعدادات الواجهة، وخيار الجدار الناري لكل عميل

الاتصال من جهاز Linux

على الهواتف والحواسيب ذات الواجهة الرسومية GUI تستخدم التطبيق، أما على سيرفر أو حاسوب Linux فتستخدم سطر الأوامر Terminal كما في دليل البدء السريع لـ WireGuard:

sudo apt install -y wireguard-tools
sudo install -m 600 laptop-ahmad.conf /etc/wireguard/wg0.conf
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0

ثم تحقق من المصافحة Handshake ومن وصولك إلى السيرفر عبر النفق:

sudo wg show wg0
ping -c 3 10.8.0.1

والمخرج سوف يكون كما يلي:

  latest handshake: 1 second ago
  transfer: 476 B received, 532 B sent
...
3 packets transmitted, 3 packets received, 0% packet loss

وفي النفق الكامل تحقق أيضاً من أن حركة الإنترنت تخرج عبر wg0، حيث يجب أن يعيد الأمر ip route get 1.1.1.1 النتيجة dev wg0 src 10.8.0.2، وأن ينجح أي طلب HTTPS خارجي، وهذا يعني أن السيرفر يمرر حركة العملاء ويترجم عناوينها (MASQUERADE) كما ينبغي.

كيف تتأكد أن النفق يعمل Verification

  • الأمر docker compose ps يعرض ال Container بحالة healthy، والسبب أن فحص الصحة Health Check المدمج يتحقق من وجود الواجهة wg0، ولاحظ أن الحالة تبقى starting في الدقيقة الأولى.
  • الأمر docker compose exec wg-easy wg show يعرض كل عميل متصل مع قيمة latest handshake حديثة، والواجهة تعرض بجانب كل عميل وقت آخر اتصال وحجم الحركة.
  • الأمر ping 10.8.0.1 ينجح من أي جهاز متصل، والخدمات الداخلية تفتح.
  • في النفق الكامل، أي موقع يعرض عنوانك العام سوف يظهر فيه عنوان السيرفر وليس عنوان شبكتك.
  • من خارج الشبكة، المنفذ 51821 غير متاح على العنوان العام، والواجهة لا تفتح إلا عبر https://wg.example.com ومن العناوين المسموح بها وحدها.
  • الأمر docker compose exec wg-easy cli clients:list يسرد العملاء كما تراهم في الواجهة، وبقية أوامر هذه الأداة في توثيق CLI.

كيف تحمي الواجهة والأجهزة Security

  • الواجهة أخطر من النفق. WireGuard لا يرد على أي حزمة Packet لا تحمل مفتاحاً صحيحاً، فلا يمكن حتى اكتشاف منفذه بالمسح Port Scanning، أما من يدخل الواجهة فيستطيع أن ينشئ لنفسه عملاء، لذلك قيدها بقائمة وصول، وفعل التحقق بخطوتين 2FA من صفحة الحساب Account. وانتبه إلى أن واجهة ال API تعتمد مصادقة Basic، وتتوقف عن العمل لهذا الحساب عندما تفعل التحقق بخطوتين.
  • عميل لكل جهاز، وتاريخ انتهاء للحسابات المؤقتة، وراجع القائمة دورياً واحذف كل عميل لم يتصل منذ أشهر.
  • أقل قدر ممكن من الصلاحيات Least Privilege: فعل الجدار الناري لكل عميل وحدد فيه ما يحتاجه كل جهاز، حتى يبقى الضرر محدوداً إذا سرق الجهاز، والسبب أن النفق الجزئي وحده يستطيع المستخدم تغييره من جهازه كما ذكرنا.
  • حدث ال Image بانتظام، فـ الإصدار 15.4 نفسه جاء بتحسينات أمنية في الواجهة.
  • بعد نقل الأدوات الإدارية خلف VPN، اضبط قوائم الوصول في ال Reverse Proxy لتسمح بالشبكة 10.8.0.0/24 وتمنع ما سواها.

النسخ الاحتياطي Backup والاستعادة Restore

كل شيء في ال Volume etc_wireguard: الملف wg-easy.db وفيه العملاء ومفاتيحهم الخاصة وإعدادات الواجهة، والملف wg0.conf الذي يولده wg-easy، لذلك أوقف الخدمة لحظات حتى تحصل على نسخة متسقة من قاعدة SQLite:

cd /opt/wg-easy
docker compose down
docker run --rm -v etc_wireguard:/etc/wireguard:ro -v "$PWD":/backup alpine:3.24 tar czf /backup/wg-easy-$(date +%F).tar.gz -C /etc/wireguard .
docker compose up -d

وللاستعادة على سيرفر جديد انقل الملف compose.yaml، ووجه vpn.example.com إلى العنوان الجديد، ثم نفذ الأوامر التالية، ولن يحتاج العملاء إلى أي تغيير لأن مفاتيح السيرفر انتقلت معه:

cd /opt/wg-easy
docker volume create etc_wireguard
docker run --rm -v etc_wireguard:/etc/wireguard -v "$PWD":/backup alpine:3.24 tar xzf /backup/wg-easy-2026-09-26.tar.gz -C /etc/wireguard
docker compose up -d

والنسخة تحمل المفاتيح الخاصة لكل الأجهزة ومفتاح السيرفر، لذلك شفرها قبل نقلها، بالأمر gpg --symmetric مثلاً، أو بأداة نسخ احتياطي تشفر افتراضياً مثل restic.

التحديث Upgrade إلى إصدار أحدث

  1. راجع صفحة الإصدارات، فداخل الإصدار الرئيسي Major Version رقم 15 لا يتوقع تغيير يعطل الإعداد Breaking Change، أما الانتقال من 14 إلى 15 فتغيير كبير فيه قاعدة بيانات جديدة ومعالج للاستيراد، وله دليل ترحيل Migration خاص في التوثيق.
  2. خذ نسخة احتياطية.
  3. غير الوسم Tag إلى رقم الإصدار الجديد كاملاً، ثم نفذ:
cd /opt/wg-easy
docker compose pull
docker compose down
docker compose up -d
docker compose logs --tail 30 wg-easy

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

مشكلات شائعة وحلولها Troubleshooting

التطبيق متصل، لكن لا توجد مصافحة ولا تمر أي حركة

WireGuard لا يعرض رسالة صريحة عندما يفشل الاتصال، فإذا لم يظهر latest handshake في مخرج wg show فالحزم لا تصل إلى السيرفر، وتحقق بالترتيب: هل يشير سجل DNS للنطاق vpn.example.com إلى السيرفر؟ هل المنفذ UDP مفتوح في جدار المزود؟ وهذا هو السبب الأشيع، حيث يفتح الكثيرون منفذ TCP بالخطأ. هل قيمة Endpoint في ملف العميل صحيحة؟ وعلى السيرفر ترى الحزم الواردة بالأمر sudo tcpdump -ni any udp port 51820.

المصافحة ناجحة، لكن لا يوجد اتصال بالإنترنت في النفق الكامل

الخلل هنا في التمرير أو في ترجمة العناوين NAT، لذلك تأكد أولاً من وجود السطر net.ipv4.ip_forward=1 في sysctls، ثم تحقق من قاعدة الترجمة داخل ال Container، حيث يجب أن يعرض الأمر docker compose exec wg-easy iptables -t nat -S | grep MASQUERADE السطر -s 10.8.0.0/24 -o eth0 -j MASQUERADE، وأن يعرض الأمر docker compose exec wg-easy ip route المخرج الافتراضي عبر dev eth0 نفسها. فإذا كان المخرج عبر eth1، فالسطران interface_name وgw_priority غير موجودين في ملفك، والقاعدة تترجم الحركة على واجهة لا تمر بها. وإذا كانت المواقع تفتح بعنوان IP ولا تفتح بالاسم، فالمشكلة في DNS، فراجع حقل DNS في الإعداد.

بعض المواقع لا يكتمل تحميلها أو تتوقف

هذه علامة معروفة على مشكلة في قيمة MTU، خاصة عبر شبكات الجوال أو اتصالات PPPoE، والحل أن تخفض MTU للعميل، أو للجميع من صفحة Config، إلى 1380 أو 1280، ثم تنزل الإعداد من جديد.

الواجهة لا تسمح بالدخول عبر http://

هذا مقصود كما ذكرنا، فاستخدم HTTPS عبر Reverse Proxy، أو نفق SSH مع INSECURE: "true" بشرط أن يكون المنفذ منشوراً على 127.0.0.1 وحده.

نسيت كلمة مرور المدير

نفذ على السيرفر الأمر docker compose exec -it wg-easy cli db:admin:reset، وسوف يطلب منك كلمة المرور الجديدة.

الهاتف يفقد الاتصال بعد مدة من الخمول Idle

السبب أن ال Router أو شبكة الجوال أسقط جلسة UDP، والحل أن تضبط Persistent Keepalive على 25 لذلك العميل، ثم تستورد إعداده من جديد.

فشل إنشاء wg0 عند التشغيل

هذا يعني أن النواة لا تتضمن WireGuard أو أن الوحدة غير محملة، وعلى Ubuntu 24.04 تتحقق من ذلك بالأمر sudo modprobe wireguard && lsmod | grep wireguard. أما على السيرفرات التي تعمل بتقنية OpenVZ أو LXC فقد لا يسمح المزود بذلك إطلاقاً، وهذا أحد أسباب تفضيل KVM كما يشرح دليل كيف تختار خادماً افتراضياً VPS.

الخلاصة

وصلنا لنهاية الموضوع، وأهم ما فيه:

  • لوحات الإدارة لا مكان لها على العنوان العام، فضعها خلف VPN ولا تكتف بكلمة المرور.
  • لا تنشر من wg-easy إلا 51820/udp، واجعل الواجهة خلف Reverse Proxy بـ HTTPS وقائمة وصول، أو على 127.0.0.1 عبر نفق SSH.
  • عندما يتصل ال Container بأكثر من شبكة، ثبت interface_name وgw_priority حتى تعمل ترجمة العناوين في النفق الكامل.
  • AllowedIPs للتوجيه فقط، أما القيد الحقيقي فهو الجدار الناري لكل عميل الذي يطبقه السيرفر.
  • عميل لكل جهاز، وتاريخ انتهاء للحسابات المؤقتة، ونسخة احتياطية مشفرة لأنها تحمل كل المفاتيح.

سجل التحديثات

  • سبتمبر 2026: كتابة الدليل واختباره على wg-easy v15.4.0.
  • أكتوبر 2026: مراجعة تقنية، أضفنا فيها interface_name وgw_priority إلى ملف Compose بعد أن تبين في الاختبار أن ترجمة العناوين لا تعمل في النفق الكامل عندما يتصل ال Container بشبكة proxy، وحذفنا ذكر متغير غير موجود في wg-easy 15، ووضحنا أن AllowedIPs ليس قيداً أمنياً.
نشرة عرب رووت | ArabRoot

معرفة تستحق مكاناً في بريدك.

مقالات مختارة وأدوات مفيدة وأفكار لمشروعك القادم، في رسالة واحدة كل أسبوع.

يمكنك إلغاء الاشتراك متى شئت. الخصوصية

تم استلام طلبك. افتح بريدك واضغط رابط التأكيد لإتمام الاشتراك.