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

تشغيل خادمك من إنترنت المنزل: CGNAT وDDNS وCloudflare Tunnel

هل يمكنك تشغيل خدماتك من اتصال الإنترنت في منزلك؟ يشرح هذا الدليل كيف تعرف ما يسمح به اتصالك، ومتى يكفي توجيه المنافذ، ولماذا يكون Cloudflare Tunnel غالباً الحل الأسهل والأكثر أماناً.

تشغيل خادمك من إنترنت المنزل: CGNAT وDDNS وCloudflare Tunnel

لنفرض أن لديك في المنزل أو المكتب جهازاً صغيراً، حاسوباً قديماً أو Raspberry Pi أو جهاز تخزين شبكي NAS، وتريد أن تشغل عليه خدماتك بدل أن تدفع اشتراكاً شهرياً لسيرفر في السحابة، فالفكرة مغرية لأن مساحة التخزين Storage عندك كبيرة ورخيصة، وبياناتك تحت سقف بيتك حرفياً. ولكن سوف تجد أن اتصال الإنترنت المنزلي مصمم لكي تطلب أنت من الإنترنت، وليس لكي يطلب الإنترنت منك، فالزائر الذي يكتب اسم موقعك من الخارج لا يعرف طريقاً إلى جهاز يجلس خلف ال Router في منزلك.

والحل البسيط الذي يخطر على البال هو أن تدخل إلى لوحة ال Router وتفتح منفذاً، ثم تعطي الناس عنوانك العام، ولكن هذا الحل يفشل عند أغلب الناس لثلاثة أسباب: فقد لا يكون لديك عنوان عام Public IP أصلاً لأن مزود الخدمة يضعك خلف CGNAT، وإذا كان لديك عنوان عام فهو غالباً يتغير كل بضعة أيام، وإذا ثبت العنوان وفتحت المنفذ فقد أصبح جهاز في منزلك مكشوفاً للإنترنت كله. لذلك سوف نمر على هذه العقبات بالترتيب، ثم ننتقل إلى الطريق الذي نوصي به في أغلب الحالات، وهو Cloudflare Tunnel، حيث يتجاوز هذه العقبات كلها باتصال صادر Outbound يبدؤه جهازك بنفسه.

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

  • كيف تعرف هل لديك عنوان عام، أم أنك خلف CGNAT.
  • العنوان الثابت والعنوان المتغير، وكيف يعطيك DNS الديناميكي Dynamic DNS اسماً ثابتاً لعنوان يتغير.
  • توجيه المنافذ Port Forwarding بالطريقة الصحيحة، وما الذي لا يجب أن توجهه أبداً.
  • تشغيل Cloudflare Tunnel في Docker بنفق مؤقت للتجربة، ثم بنفق دائم تديره من اللوحة أو من ملف إعداد.
  • مقارنة الطرق من ناحية الأمان، ثم التحقق والنسخ الاحتياطي والتحديث وأشهر المشكلات.

وقبل أن تبدأ، لا تستضف من المنزل خدمة حرجة لعمل مؤسستك تحتاج إلى التوافرية High Availability، والسبب أن الكهرباء والإنترنت في المنزل ينقطعان، وسرعة الرفع Upload في أغلب الاشتراكات أقل بكثير من سرعة التنزيل Download، وفي هذه الحالة يناسبك سيرفر افتراضي صغير، وتجد معايير اختياره في دليل كيف تختار خادماً افتراضياً VPS. وكثيرون يجمعون بين الاثنين، فتبقى البيانات الكبيرة في المنزل، وتكون نقطة الدخول Entry Point على سيرفر VPS.

ما تحتاجه قبل أن تبدأ

  • جهاز يعمل على مدار الساعة، عليه Linux وDocker، وإذا لم يكن Docker جاهزاً فاتبع دليل تثبيت Docker على Ubuntu. والأفضل أن يتصل بالشبكة بكابل وليس عبر Wi-Fi، وأن يكون موصولاً بمزود طاقة احتياطي UPS إن أمكن.
  • صلاحية الدخول إلى لوحة إدارة ال Router، إذا اخترت توجيه المنافذ.
  • نطاق Domain تملكه، ولاحظ أن مسار Cloudflare Tunnel يشترط أن تكون خوادم أسماء النطاق Nameservers لدى Cloudflare، والخطة المجانية تكفي.
  • راجع شروط مزود خدمة الإنترنت ISP، فبعض العقود المنزلية تمنع تشغيل السيرفرات، أو تحجب الاتصالات الواردة Inbound على المنافذ 25 و80 و443.

هل لديك عنوان عام أصلاً؟ اكتشاف CGNAT

عندما نفدت عناوين IPv4، أصبح كثير من مزودي الإنترنت يضعون عدداً من المشتركين خلف عنوان عام واحد، وهذا شائع في شبكات الجوال وفي كثير من اشتراكات الألياف الحديثة، واسم هذه التقنية الترجمة على مستوى المزود Carrier-Grade NAT واختصاراً CGNAT. وفي هذه الحالة يحصل ال Router لديك على عنوان خاص Private IP من شبكة المزود وليس على عنوان عام، والنتيجة أنه لا يوجد منفذ تستطيع فتحه، لأن الباب الخارجي عند المزود وليس عندك، فأنت تشبه ساكناً في عمارة يستطيع أن يفتح باب شقته كما يشاء، ولكن باب العمارة مع الحارس.

ولكي تعرف وضعك، قارن بين عنوانين:

  1. عنوان WAN كما يظهر في صفحة الحالة في ال Router (Status أو Internet).
  2. عنوانك العام كما يراه الإنترنت، وتعرفه بالأمر التالي من أي جهاز في المنزل:
curl -4 -s https://api.ipify.org; echo

إذا تطابق العنوانان فلديك عنوان عام، وإذا اختلفا فأنت خلف طبقة NAT إضافية. وإذا كان عنوان WAN ضمن النطاق 100.64.0.0/10 (من 100.64.x.x إلى 100.127.x.x)، فهو من مساحة العناوين التي خصصتها RFC 6598 لشبكات CGNAT تحديداً، والفحص التالي يكشف ذلك:

ip=100.72.13.5
IFS=. read a b c d <<<"$ip"
if [ "$a" -eq 100 ] && [ "$b" -ge 64 ] && [ "$b" -le 127 ]; then echo "$ip is CGNAT (100.64.0.0/10)"; fi
100.72.13.5 is CGNAT (100.64.0.0/10)

وهناك مؤشر آخر، وهو أن تشغل الأمر traceroute -n 1.1.1.1 من جهاز في المنزل، فإذا ظهر بعد ال Router مباشرة عنوان من 100.64.0.0/10 أو من شبكة خاصة Private Network، فهذا يعني أن هناك طبقة NAT عند المزود.

وإذا كنت خلف CGNAT فأمامك ثلاثة خيارات: الأول أن تطلب من المزود عنواناً عاماً، فبعض المزودين يعطيه مجاناً عند الطلب وبعضهم بمقابل. والثاني IPv6 إذا كان مزودك يوفره، حيث يحصل كل جهاز على عنوان عام ولا توجد ترجمة عناوين، ولكن جدار الحماية Firewall في ال Router يمنع الاتصالات الواردة افتراضياً فتحتاج إلى قاعدة تسمح بها لعنوان السيرفر، والزوار الذين ليس لديهم IPv6 لن يصلوا إليه مباشرة. والثالث أن تتجاوز المشكلة كلها بنفق Tunnel صادر، كما سيأتي في قسم Cloudflare Tunnel.

الوصول إلى جهاز المنزل من العمل خلف CGNAT

وهذه حالة من تجربة شخصية، فاتصال منزلي خلف CGNAT، وشبكة العمل لا تسمح بتثبيت أي برنامج VPN ولا يخرج منها إلا اتصال سطح المكتب البعيد Remote Desktop Protocol واختصاراً RDP، لذلك أصل إلى جهازي في المنزل عبر سيرفر آخر: جهاز المنزل يفتح بنفسه نفق SSH عكسياً Reverse SSH Tunnel إلى سيرفر VPS، ومن العمل أتصل ب RDP بهذا السيرفر فيوصلني النفق إلى جهاز المنزل. والاتجاه هنا هو سر الحل، فالاتصال يخرج من المنزل ولا يدخل إليه، وبالتالي لا يهم أن العنوان غير عام. أما الخطوات كاملة، أي كيف تحصر المنفذ على عنوان العمل وحده وكيف تبقي النفق متصلاً، فقد شرحناها في شرح الأنفاق Tunnels في الشبكات.

هل تحتاج إلى عنوان ثابت؟

حتى لو كان لديك عنوان عام، فهو يتغير غالباً في الاشتراكات المنزلية، إما عند إعادة تشغيل ال Router أو كل بضعة أيام، والعنوان الثابت Static IP خدمة إضافية بمقابل عند أغلب المزودين. فهل تحتاجه فعلاً؟ الجدول التالي يقارن بين الخيارات الثلاثة:

عنوان ثابتعنوان متغير مع DDNSنفق صادر
التكلفةرسوم شهرية في الغالبمجانيمجاني للاستخدام الأساسي
عند تغير العنوانلا يتغيرانقطاع لبضع دقائق حتى يتحدث سجل DNS Recordلا أثر له، فالنفق يعيد الاتصال وحده
يعمل خلف CGNATنعم، لأن المزود يمنحك عنواناً عاماً فعلياًلا يعملنعم
البريد الإلكتروني Emailممكن مع سجل PTR، مع أن كثيراً من قوائم الحظر Blocklists تحظر العناوين المنزليةغير عمليغير مناسب للبريد
يكشف عنوان منزلكنعمنعملا يكشفه

اسم ثابت لعنوان يتغير: DDNS

فكرة DNS الديناميكي Dynamic DNS واختصاراً DDNS بسيطة، وهي برنامج صغير على جهازك يراقب عنوانك العام، ويحدث سجل A للنطاق home.example.com كلما تغير العنوان. وكثير من أجهزة ال Router فيها عميل DDNS Client مدمج يدعم مزودين محددين، فإذا كان مزودك منهم فهذا أبسط خيار.

أما إذا كان نطاقك لدى Cloudflare، فسوف نستخدم السكربت التالي، وهو يعمل عبر واجهة Cloudflare البرمجية API لتعديل سجلات DNS. أنشئ أولاً سجل A للاسم يدوياً من اللوحة، ثم أنشئ توكن API Token بصلاحية Zone › DNS › Edit على هذه المنطقة Zone وحدها، والسبب أن التوكن سوف يبقى في ملف على جهاز منزلي، فإذا تسرب لا يستطيع صاحبه أن يعبث بباقي نطاقاتك. بعد ذلك ثبت الأدوات اللازمة:

sudo apt install -y curl jq

واحفظ الأسرار Secrets في الملف /etc/cf-ddns.env بصلاحية 600 حتى لا يقرأه غير root:

sudo tee /etc/cf-ddns.env >/dev/null <<'EOF'
CF_API_TOKEN=ضع-الرمز-هنا
CF_ZONE_ID=0123456789abcdef0123456789abcdef
CF_RECORD_NAME=home.example.com
EOF
sudo chmod 600 /etc/cf-ddns.env

والسكربت /usr/local/bin/cf-ddns.sh سوف يكون كما يلي:

#!/usr/bin/env bash
set -euo pipefail
source /etc/cf-ddns.env
STATE=/var/lib/cf-ddns.last
IP=$(curl -4 -fsS --max-time 10 https://api.ipify.org)
[[ $IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "bad IP: $IP" >&2; exit 1; }
[[ -f $STATE && $(cat "$STATE") == "$IP" ]] && exit 0
API=https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records
AUTH=(-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json")
ID=$(curl -fsS "${AUTH[@]}" "$API?type=A&name=$CF_RECORD_NAME" | jq -r '.result[0].id')
[[ -n $ID && $ID != null ]] || { echo "record $CF_RECORD_NAME not found" >&2; exit 1; }
curl -fsS -X PATCH "${AUTH[@]}" "$API/$ID" --data "{\"content\":\"$IP\"}" | jq -e '.success' >/dev/null
echo "$IP" > "$STATE"
logger -t cf-ddns "updated $CF_RECORD_NAME to $IP"

في السكربت أعلاه لاحظ التالي:

  • يتحقق السكربت من أن ما أعاده الموقع عنوان IPv4 صحيح قبل أن يرسله، حتى لا يكتب في السجل صفحة خطأ أو نصاً فارغاً.
  • يحفظ آخر عنوان سجله في ملف حالة، ولا يتصل بالواجهة البرمجية إلا إذا تغير العنوان، وبالتالي لا يستهلك حدود الطلبات Rate Limits وهو يعمل كل خمس دقائق.
  • يستخدم الطلب PATCH ليعدل محتوى السجل فقط، ويترك باقي إعداداته كما هي.

الآن اجعله قابلاً للتنفيذ، وجدوله ليعمل كل خمس دقائق، ثم شغله مرة يدوياً:

sudo chmod 755 /usr/local/bin/cf-ddns.sh
echo '*/5 * * * * root /usr/local/bin/cf-ddns.sh' | sudo tee /etc/cron.d/cf-ddns
sudo /usr/local/bin/cf-ddns.sh && journalctl -t cf-ddns -n 5

وإذا كان التوكن غير صالح فسوف ترفضه الواجهة برسالة مثل curl: (22) ... error: 400، ويتوقف السكربت دون أن يحفظ الحالة، فيعيد المحاولة في الدورة التالية، ومع توكن صالح يتحدث السجل. واجعل مدة بقاء السجل TTL قصيرة، 60 أو 120 ثانية، حتى يسري التغيير بسرعة.

فتح المنافذ في ال Router بالطريقة الصحيحة

ال Router يرفض كل اتصال وارد لم يطلبه جهاز داخلي، وتوجيه المنافذ Port Forwarding قاعدة تقول له: أرسل كل ما يصل على المنفذ 443 إلى الجهاز 192.168.1.50 على المنفذ 443. والشاشات تختلف من جهاز إلى آخر، ولكن الخطوات واحدة:

  1. أعط السيرفر عنواناً داخلياً ثابتاً عن طريق حجز DHCP Reservation في ال Router، وليس بتعيينه يدوياً على السيرفر، والسبب أن ال Router يبقى هو المرجع الوحيد للعناوين فلا يعطي عنوان السيرفر لجهاز آخر.
  2. في صفحة Port Forwarding أو NAT أو Virtual Server، وجه المنفذ الخارجي 443/tcp إلى 192.168.1.50:443، والمنفذ 80/tcp إلى 192.168.1.50:80، ولاحظ أن المنفذ 80 لازم للتحقق عبر HTTP (HTTP Challenge) في Let's Encrypt. وأضف 51820/udp إذا كنت سوف تشغل WireGuard.
  3. شغل على السيرفر Reverse Proxy واحداً يستقبل المنفذين 80 و443 ويوزع الطلبات على الخدمات، مثل Nginx Proxy Manager، ولا توجه منفذاً مستقلاً لكل تطبيق.
  4. عطل UPnP في ال Router، لأنها تسمح لأي جهاز داخلي أن يفتح منافذ لنفسه دون علمك.

واختبر الوصول من شبكة أخرى مثل بيانات الهاتف، وليس من شبكة المنزل، والسبب أن كثيراً من أجهزة ال Router لا تدعم الوصول إلى عنوانها العام من داخل الشبكة، وهي الخاصية التي تسمى NAT Loopback أو Hairpin. ومن الخارج نفذ:

curl -sI https://home.example.com | head -n 1
nc -vz home.example.com 443
🛑
كل منفذ توجهه يجعل جهازاً في منزلك هدفاً مباشراً لعمليات المسح الآلي Automated Scanning على الإنترنت، وهذا الجهاز يشارك نفس الشبكة مع حواسيب العائلة وهواتفها. لذلك لا توجه أبداً المنافذ الإدارية، مثل SSH (22) أو لوحات الإدارة أو قواعد البيانات Databases أو SMB، وللوصول الإداري من الخارج استخدم شبكة خاصة افتراضية VPN كما في دليل شبكة خاصة مع WireGuard وwg-easy. وإن أمكنك، فضع السيرفر في شبكة منفصلة (VLAN أو منطقة DMZ حقيقية) تمنعه من الوصول إلى بقية أجهزة المنزل.

الطريق الذي نوصي به: Cloudflare Tunnel

بدل أن تفتح منفذاً في ال Router، سوف تشغل على السيرفر برنامجاً صغيراً اسمه cloudflared، وهذا البرنامج يفتح اتصالات صادرة مشفرة Encrypted إلى شبكة Cloudflare ويبقيها مفتوحة. وعندما يطلب زائر app.example.com يصل طلبه إلى Cloudflare أولاً، فتمرره عبر ذلك الاتصال المفتوح إلى cloudflared، وهو بدوره يسلمه إلى ال Container المحلي، أي أن الباب يفتح من الداخل ولا يحتاج أحد إلى طرقه من الخارج. فماذا تكسب عملياً؟

  • يعمل النفق خلف CGNAT، ومع العنوان المتغير، ومع المزود الذي يحجب المنفذين 80 و443، ولا يحتاج إلى DDNS.
  • لا يبقى في ال Router أي منفذ وارد مفتوح، ولا يظهر عنوان منزلك في سجلات DNS.
  • تصدر Cloudflare شهادة TLS Certificate العامة تلقائياً.
  • تستطيع أن تضع طبقة تسجيل دخول عبر Cloudflare Access، وهي جزء من منصة Zero Trust، أمام أي تطبيق دون أن تعدل فيه شيئاً.

تجربة سريعة دون حساب

قبل الإعداد الدائم، تأكد أن شبكتك تسمح ل cloudflared بالاتصال بالخارج، واستخدم لذلك نفقاً مؤقتاً Quick Tunnel على نطاق عشوائي من trycloudflare.com. وملف Compose التالي للتجربة فقط:

services:
  whoami:
    image: traefik/whoami:v1.11.0
    restart: unless-stopped

  cloudflared:
    image: cloudflare/cloudflared:2026.9.3
    command: tunnel --no-autoupdate --url http://whoami:80
    depends_on:
      - whoami
docker compose up -d
docker compose logs cloudflared | grep -A1 'quick Tunnel has been created'

وخلال ثوان سوف يظهر عنوان مثل https://considerations-logistics-act-soonest.trycloudflare.com، وطلبه من الإنترنت يجب أن يعود بالرمز 200. ولاحظ أن التطبيق تصله ترويسات Headers منها X-Forwarded-Proto: https وCf-Connecting-Ip، والأخيرة فيها عنوان الزائر الحقيقي. وقبل ذلك يطبع cloudflared جدولاً بنتائج فحوص الاتصال Connectivity Checks، وهو يفيدك في التشخيص Troubleshooting:

|  UDP Connectivity  region1.v2.argotunnel.com  PASS    QUIC connection successful    |
|  TCP Connectivity  region1.v2.argotunnel.com  PASS    HTTP/2 connection successful  |
|  Cloudflare API    api.cloudflare.com:443     PASS    API is reachable              |
|  SUMMARY: Environment is healthy. cloudflared will use 'quic' as primary protocol.  |

وهذا النفق السريع للتجربة فقط، والسبب أن عنوانه يتغير مع كل تشغيل، ولا يوجد ضمان لتوفره، ولا يقبل أكثر من 200 طلب متزامن. أوقفه بالأمر docker compose down، وانتقل إلى النفق المسمى Named Tunnel.

نفق دائم تديره من لوحة Cloudflare

هذه الطريقة تسمى remotely-managed tunnel، وهي الأسهل في الصيانة، لأنك تدير القواعد Rules من اللوحة، والسيرفر لا يحتاج إلا إلى توكن واحد. والخطوات في لوحة Cloudflare كما يلي، مع العلم أن أسماء بعض العناصر قد تتغير قليلاً مع تحديثات الواجهة:

  1. افتح Networking ثم Tunnels ثم Create a tunnel، وسم النفق (home-server).
  2. في صفحة التثبيت اختر Docker، وسوف تعرض اللوحة أمراً فيه --token eyJ...، فانسخ منه التوكن فقط.
  3. في تبويب Routes اختر Add route ثم Published application، وأضف لكل خدمة النطاق الفرعي Subdomain app والنطاق example.com، وفي Service URL اختر النوع HTTP والعنوان whoami:80. وسوف تنشئ Cloudflare سجل DNS من نوع CNAME تلقائياً.

وعلى السيرفر أنشئ المجلد /opt/cloudflared، وضع فيه ملف .env بصلاحية 600:

sudo mkdir -p /opt/cloudflared
sudo chown $USER: /opt/cloudflared
cd /opt/cloudflared
printf 'TUNNEL_TOKEN=%s\n' 'الصق-الرمز-هنا' > .env
chmod 600 .env

ثم أنشئ الملف /opt/cloudflared/compose.yaml، وسوف نضع فيه cloudflared على شبكة proxy التي تعمل عليها تطبيقاتك، وبالتالي يصل إليها بأسماء ال Containers دون نشر أي منفذ:

services:
  cloudflared:
    image: cloudflare/cloudflared:2026.9.3
    container_name: cloudflared
    restart: unless-stopped
    command: tunnel --no-autoupdate --metrics 127.0.0.1:2000 run
    environment:
      TUNNEL_TOKEN: ${TUNNEL_TOKEN}
    networks:
      - proxy
    healthcheck:
      test: ["CMD", "cloudflared", "tunnel", "--metrics", "localhost:2000", "ready"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 20s

networks:
  proxy:
    external: true

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

  • --no-autoupdate: نحدث ال Container بتغيير الوسم Tag، وليس بالتحديث الذاتي Auto-update، حتى تعرف دائماً أي إصدار يعمل عندك.
  • --metrics: يشغل سيرفر المقاييس Metrics داخل ال Container، ومنه النقطة /ready، وعليها يعتمد فحص الصحة Health Check عبر الأمر cloudflared tunnel ready، والسبب أن ال Image ليس فيها Shell ولا curl. وبعد اتصال النفق تصبح حالة ال Container healthy، وتعيد النقطة /ready قيمة مثل "readyConnections":1.
  • التوكن في ملف .env وليس في ملف Compose، حتى لا يصل إلى Git، لأن من يملك التوكن يستطيع أن يشغل نفقك من أي مكان.
docker network create proxy
docker compose up -d
docker compose ps
docker compose logs --tail 20 cloudflared

وعند تشغيل الأوامر ابحث في السجل Log عن العبارة Registered tunnel connection، وسوف تجدها عادة أربع مرات، كل مرة اتصال بمركز بيانات Data Center مختلف، وفي لوحة Cloudflare تصبح حالة النفق Healthy.

هل تحتاج إلى Reverse Proxy خلف النفق؟

تستطيع أن توجه كل اسم في النفق إلى ال Container الخاص به مباشرة (http://gitea:3000)، وهذا يكفي غالباً. أما إذا كان لديك Nginx Proxy Manager بقوائم وصول Access Lists وإعدادات جاهزة، فوجه كل الأسماء إلى http://npm:80 ودعه يوزع الطلبات حسب اسم النطاق، وفي هذه الحالة لا تفعل Force SSL في NPM، والسبب أن الاتصال بين cloudflared وNPM يجري عبر HTTP بينما يرى المستخدم HTTPS، أو فعل خيار الثقة بترويسة البروتوكول القادمة من ال Proxy كما في دليل NPM، وإلا فسوف تدخل في حلقة تحويل Redirect Loop لا تنتهي.

إذا كنت تفضل القواعد في ملف إعداد

إذا كنت تفضل حفظ القواعد في Git بدل اللوحة، فأنشئ النفق من الطرفية Terminal (cloudflared tunnel login ثم cloudflared tunnel create home-server ثم cloudflared tunnel route dns home-server app.example.com)، ثم اكتب ملف الإعداد config.yml:

tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef
credentials-file: /etc/cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
ingress:
  - hostname: app.example.com
    service: http://whoami:80
  - hostname: git.example.com
    service: http://gitea:3000
  - service: http_status:404

ولاحظ أن القاعدة الأخيرة بدون اسم، وهي إلزامية لأنها ترد على أي اسم غير معروف. افحص الملف قبل التشغيل، ثم اختبر أي قاعدة تطابق رابطاً معيناً:

docker run --rm -v "$PWD/config.yml:/etc/cloudflared/config.yml:ro" cloudflare/cloudflared:2026.9.3 tunnel --config /etc/cloudflared/config.yml ingress validate
docker run --rm -v "$PWD/config.yml:/etc/cloudflared/config.yml:ro" cloudflare/cloudflared:2026.9.3 tunnel --config /etc/cloudflared/config.yml ingress rule https://git.example.com/user/repo

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

Validating rules from /etc/cloudflared/config.yml
OK
Using rules from /etc/cloudflared/config.yml
Matched rule #1
	hostname: git.example.com
	service: http://gitea:3000

ولاحظ أن الترقيم يبدأ من صفر، فالقاعدة رقم 1 هي الثانية في الملف. بعد ذلك شغل ال Container بالأمر tunnel --no-autoupdate --config /etc/cloudflared/config.yml run، وركب Mount فيه المجلد الذي فيه config.yml وملف بيانات الاعتماد Credentials .json.

أي طريق أقل خطراً؟

توجيه المنافذCloudflare TunnelVPS وسيط مع WireGuard
منافذ واردة في المنزل80 و443 على الأقللا توجد منافذ واردةلا توجد منافذ واردة، فالسيرفر المنزلي هو الذي يتصل بال VPS
عنوان المنزل مكشوفنعملالا
من يطلع على الحركة Trafficأنت وحدكCloudflare، لأنها تنهي جلسة TLS (TLS Termination) وترى الحركة غير مشفرةأنت وحدك
البروتوكولات ProtocolsكلهاHTTP وHTTPS للجمهور، وغيرها يحتاج إلى تطبيق cloudflared أو WARP عند المستخدمكلها
القيودلا يعمل خلف CGNATشروط الاستخدام تقيد بث الفيديو والملفات الكبيرة دون خدمات مدفوعة، والطلب الواحد في الخطة المجانية محدود بحجم 100 ميجابايت وبمهلة انتظار للرد 125 ثانيةتكلفة VPS وإدارته
الاعتماد على طرف ثالث Third Partyلا يوجدكامل، فإذا تعطل حسابك أو تعطلت Cloudflare تعطلت خدماتكمزود VPS فقط

وقد يتساءل البعض: إذا كان النفق يخفي عنوان المنزل ولا يفتح أي منفذ، فلماذا لا نستخدمه لكل شيء؟ والإجابة على ذلك أن جلسة TLS تنتهي عند Cloudflare، فهي قادرة تقنياً على رؤية كل ما يمر بها، ومنه كلمات المرور والملفات، وهذا ما يفعله ال Proxy في أي شبكة CDN، وهو مقبول عادة لمدونة أو لأداة يستخدمها فريق. أما البيانات الحساسة أو الخاضعة لمتطلبات تنظيمية Compliance، أو إذا كانت الخصوصية هي سبب استضافتك الذاتية Self-Hosting أصلاً، فالحل الأنسب هو سيرفر VPS وسيط تملكه، يشغل ال Reverse Proxy وWireGuard، ويتصل به سيرفر المنزل عبر نفق صادر، وبالتالي تبقى مفاتيح التشفير Encryption Keys عندك.

📌
في 18 نوفمبر 2025 أدى تغيير في صلاحيات إحدى قواعد البيانات لدى Cloudflare إلى مضاعفة حجم ملف إعداد يستخدمه نظام إدارة البوتات Bot Management، فتجاوز الحد الذي يتحمله ال Proxy الأساسي، وظهرت أخطاء 5xx لزوار عدد كبير من المواقع من الساعة 11:20 بتوقيت UTC، ولم تعد الحركة الأساسية إلى وضعها الطبيعي إلا قرابة 14:30، كما فشل تسجيل الدخول عبر Cloudflare Access لكثير من المستخدمين، بحسب التقرير الرسمي من Cloudflare. والدرس أن خدماتك خلف النفق تتوقف عندما يتوقف المزود مهما كان سيرفرك المنزلي سليماً، لذلك اعرف مسبقاً طريقاً بديلاً للوصول الإداري مثل VPN، ولا تجعل خدمة لا تحتمل التوقف تعتمد على مزود واحد.
⚠️
النفق لا يجعل التطبيق آمناً، وإنما يغير طريق الوصول إليه فقط، فالتطبيق ما زال مكشوفاً للعالم بثغراته Vulnerabilities وكلمات مروره الضعيفة. لذلك حدثه باستمرار، وفعل فيه التحقق بخطوتين 2FA، وضع اللوحات الإدارية خلف Cloudflare Access أو خلف نظام دخول موحد SSO، أو لا تنشرها عبر النفق أصلاً.

كيف تتأكد أن كل شيء يعمل

  • الأمر docker compose ps يعرض ال Container cloudflared بحالة healthy، وفي السجل العبارة Registered tunnel connection.
  • من شبكة أخرى، مثل بيانات الهاتف، يعود الأمر curl -sI https://app.example.com بالرمز 200 أو بتحويل إلى صفحة الدخول.
  • الأمر dig +short app.example.com يعيد عناوين Cloudflare وليس عنوان منزلك.
  • لا توجد قواعد لتوجيه المنافذ في ال Router، وUPnP معطلة، وفحص المنافذ لعنوانك العام من الخارج (بالأمر nmap -Pn من سيرفر VPS مثلاً) لا يجد أي منفذ مفتوح.
  • التطبيق يرى عنوان الزائر الحقيقي في Cf-Connecting-Ip أو X-Forwarded-For، إذا كنت تحتاجه في السجلات.
  • مع DDNS: غير العنوان بإعادة تشغيل ال Router، ثم تأكد أن journalctl -t cf-ddns سجل التحديث خلال خمس دقائق.

ما الذي تنسخه وكيف تستعيده

  • النفق الذي تديره من اللوحة: على السيرفر يوجد فقط /opt/cloudflared/compose.yaml و.env، والقواعد محفوظة في حساب Cloudflare. احفظ الملفين في نسخة احتياطية Backup في مكان آمن ومشفر، لأن .env فيه التوكن، واكتب قائمة الأسماء والخدمات في مستند داخلي حتى تعيد بناءها عند الحاجة.
  • النفق بملف محلي: الملف config.yml، وملف بيانات الاعتماد .json، والملف cert.pem الناتج عن tunnel login إن كنت احتفظت به.
  • DDNS: الملفات /usr/local/bin/cf-ddns.sh و/etc/cf-ddns.env و/etc/cron.d/cf-ddns.
sudo tar czf ~/home-edge-$(date +%F).tar.gz /opt/cloudflared /usr/local/bin/cf-ddns.sh /etc/cf-ddns.env /etc/cron.d/cf-ddns

وللاستعادة Restore على جهاز جديد، فك الأرشيف في /، ثم نفذ docker network create proxy وdocker compose up -d داخل /opt/cloudflared، وسوف يتصل النفق بنفس الاسم دون أي تعديل في DNS. وإذا تسرب التوكن فأعد توليده من لوحة النفق (Refresh token)، ثم حدث ملف .env.

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

أرقام إصدارات cloudflared مبنية على التاريخ (2026.9.3)، وتدعم Cloudflare الإصدارات التي لم يمض على صدورها أكثر من عام من آخر إصدار، لذلك لا تتركه طويلاً دون تحديث Upgrade. راجع صفحة الإصدارات، وغير الوسم، ثم نفذ:

cd /opt/cloudflared
docker compose pull
docker compose up -d
docker compose logs --tail 20 cloudflared

وللتحديث دون انقطاع Zero Downtime، شغل نسختين Replicas من cloudflared بنفس التوكن على جهازين، فتوزع Cloudflare الحركة بينهما، وتحدث واحدة ثم الأخرى.

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

Error 1033 أو صفحة من Cloudflare تقول إن النفق غير متاح

هذا الخطأ يعني أن النفق غير متصل، فراجع docker compose logs cloudflared. والرسالة Provided Tunnel token is not valid تعني أن التوكن ناقص أو فيه مسافات، فانسخه من جديد. أما فشل فحص UDP Connectivity فيعني أن شبكتك تحجب QUIC على المنفذ 7844، فأضف --protocol http2 إلى الأمر.

502 Bad Gateway عبر النفق

النفق يعمل، ولكن cloudflared لا يصل إلى التطبيق. تأكد أن الخدمة في اللوحة تشير إلى اسم ال Container ومنفذه الداخلي (whoami:80 وليس localhost:8080)، والسبب أن localhost داخل ال Container cloudflared يعني ال Container نفسه. وتأكد أيضاً أن ال Containers الاثنين على نفس شبكة proxy.

ERR_TOO_MANY_REDIRECTS

التطبيق أو ال Reverse Proxy الذي خلف النفق يحول طلبات HTTP إلى HTTPS، بينما يصله الطلب من cloudflared عبر HTTP، فيتكرر التحويل بلا نهاية. اجعل التطبيق يثق بترويسة X-Forwarded-Proto أو عطل التحويل فيه، ثم اضبط رابطه العام (ROOT_URL أو ما يقابله) على https://.

فشل رفع الملفات الكبيرة أو انقطاع الطلبات الطويلة

الخطة المجانية تفرض حداً لحجم جسم الطلب الواحد Request Body وهو 100 ميجابايت حالياً، وتطبيقات المزامنة Sync التي تقسم الملفات إلى أجزاء تعمل عادة، أما رفع ملف كبير دفعة واحدة فيفشل بالرمز 413. وكذلك إذا تأخر رد التطبيق أكثر من 125 ثانية، كتصدير تقرير كبير، فسوف يرى الزائر الخطأ 524. ولنقل الملفات الكبيرة استخدم VPN أو سيرفر VPS وسيطاً.

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

شغل السكربت يدوياً بالأمر sudo bash -x /usr/local/bin/cf-ddns.sh، فإذا أعادت الواجهة 400 أو 403 فالتوكن خاطئ أو ليست له صلاحية على المنطقة، والرسالة record ... not found تعني أن السجل غير موجود أو أن الاسم لا يطابقه. وإذا كان العنوان المكتشف من نطاق CGNAT أو عنواناً خاصاً، فالمشكلة ليست في السكربت، وإنما أنت خلف CGNAT.

يعمل من الخارج ولا يعمل من داخل المنزل (مع توجيه المنافذ)

ال Router لا يدعم NAT Loopback، والحل سيرفر DNS داخلي يعيد العنوان الداخلي للنطاق، مثل AdGuard Home أو Pi-hole، أو Cloudflare Tunnel الذي لا يتأثر بهذه المشكلة.

الخلاصة

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

  • ابدأ بمقارنة عنوان WAN بعنوانك العام، فإذا كان من 100.64.0.0/10 فأنت خلف CGNAT ولن يفيدك فتح أي منفذ.
  • العنوان المتغير يحله DDNS، ولكن توجيه المنافذ يكشف عنوان منزلك ويجعل جهازك هدفاً للمسح الآلي، فلا توجه إلا 80 و443 إلى Reverse Proxy واحد، ولا توجه المنافذ الإدارية أبداً.
  • Cloudflare Tunnel يعمل خلف CGNAT دون أي منفذ وارد، وهو الطريق الأنسب لأغلب الخدمات المنزلية، مع العلم أن Cloudflare ترى الحركة وأن خدماتك تتوقف إذا توقفت.
  • للبيانات الحساسة استخدم سيرفر VPS وسيطاً تملكه مع WireGuard، وللإدارة من الخارج استخدم VPN.
  • النفق يغير طريق الوصول فقط، فحدث التطبيق وفعل 2FA وضع اللوحات الإدارية خلف Cloudflare Access.

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

  • سبتمبر 2026: كتابة الدليل واختباره على cloudflared 2026.9.3.
  • أكتوبر 2026: مراجعة الدليل، وتحديث خطوات لوحة Cloudflare إلى Networking ثم Tunnels وتبويب Routes، وإضافة مهلة الانتظار 125 ثانية وحدود النفق السريع.
  • أكتوبر 2026: إضافة حالة الوصول إلى جهاز المنزل خلف CGNAT عبر نفق SSH عكسي، مع رابط إلى شرح الأنفاق.
نشرة عرب رووت | ArabRoot

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

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

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

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