لنفرض أن لديك سيرفراً تشغل عليه 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.
كيف يوزع 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) | |
|---|---|---|
| AllowedIPs | 0.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.docker compose down وdocker compose up -d وليس بالأمرين stop وstart، والسبب أن الواجهة وقواعد الشبكة قد تبقى في حالة غير متسقة فيفشل التشغيل التالي.كيف تفتح واجهة الإدارة Web UI بأمان
الواجهة في الإصدار 15 ترفض افتراضياً العمل عبر HTTP غير المشفر، والسبب أن كلمة مرور المدير تمر من خلالها، وكذلك ملفات الإعداد التي تحمل المفاتيح الخاصة Private Keys للعملاء، والحل الذي يلجأ إليه البعض هو تفعيل INSECURE مع نشر المنفذ على العنوان العام، وهذا الحل غير مناسب إطلاقاً لأنه يعرض كلمة المرور والمفاتيح لكل من يمر في الطريق بينك وبين السيرفر. لذلك أمامك طريقان صحيحان:
- عبر Reverse Proxy بـ HTTPS (الطريق الموصى به): أنشئ في Nginx Proxy Manager Proxy Host للنطاق
wg.example.comيوجه إلىhttp://wg-easy:51821، وفعل عليه شهادة Let's Encrypt وخيار Force SSL، ثم أضف قائمة وصول Access List تقصر الواجهة على عناوين الفريق، حتى لا تبقى صفحة الدخول مفتوحة لكل من يعرف النطاق. - عبر نفق 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أبداً مع منفذ منشور على عنوان عام، والسبب ما ذكرناه أعلاه.
معالج الإعداد الأول Setup Wizard
أول مرة تفتح فيها الواجهة يظهر معالج من خطوات قصيرة، وبعد صفحة الترحيب تنشئ حساب المدير باسم مستخدم وكلمة مرور قوية:

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

وإذا كنت تنشر الخدمة آلياً 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 العميل تلقائياً.
وأنشئ عميلاً مستقلاً لكل جهاز، ولا تستخدم ملفاً واحداً على جهازين، والسبب أن كل ملف يحمل مفتاحاً خاصاً، والجهازان اللذان يحملان المفتاح نفسه يتنازعان على الاتصال فينقطع أحدهما كلما اتصل الآخر.

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

والمثال التالي يبين ملف عميل كما تولده الواجهة، بعد اختصار المفاتيح:
[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 للإبقاء على الاتصال.
PrivateKey، ومن يحصل عليهما يدخل شبكتك باسم ذلك الجهاز، لذلك عاملهما معاملة كلمة المرور: لا تلتقط لهما صوراً، ولا ترسلهما عبر قنوات عامة، واحذف الملف من مجلد التنزيلات بعد استيراده. وإذا فقد أحد الموظفين جهازه أو غادر المؤسسة، فأوقف عميله أو احذفه من الواجهة فوراً.نفق جزئي لعميل واحد أو للجميع
لتغيير الإعداد الافتراضي للجميع افتح Admin Panel ثم Config، وعدل حقلي Allowed IPs وDNS، ولاحظ أن هذه القيم تدخل في ملفات العملاء الجدد فقط، أما العملاء الحاليون فيحتاجون إلى تنزيل ملفاتهم من جديد. وإذا كان لديك DNS داخلي، مثل AdGuard Home على 10.8.0.1، فضعه هنا مكان خوادم DNS العامة.

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

وبعد الحفظ سوف تجد أن ملف هذا العميل يتضمن:
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).

الاتصال من جهاز 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 إلى إصدار أحدث
- راجع صفحة الإصدارات، فداخل الإصدار الرئيسي Major Version رقم 15 لا يتوقع تغيير يعطل الإعداد Breaking Change، أما الانتقال من 14 إلى 15 فتغيير كبير فيه قاعدة بيانات جديدة ومعالج للاستيراد، وله دليل ترحيل Migration خاص في التوثيق.
- خذ نسخة احتياطية.
- غير الوسم 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ليس قيداً أمنياً.