# ربط نطاق مخصص

> وجّه نطاقك الخاص إلى تطبيق ويب مستضاف على Daki باستخدام Cloudflare كوكيل عكسي، مع HTTPS مجاني وتوجيه المنافذ المخصصة. يتضمن بديلًا متقدمًا هو Cloudflare Tunnel (cloudflared).

هل تريد أن يكون تطبيق الويب الخاص بك متاحًا على `yourdomain.com` بدلًا من عنوان `hostname:port`؟ يوضح لك هذا الدليل كيف توجّه نطاقك الخاص إلى خادم Daki باستخدام **Cloudflare** كوكيل عكسي مجاني. يتولى Cloudflare الـ HTTPS نيابةً عنك، ويوجّه الزوار إلى المنفذ المخصص الذي يستمع إليه تطبيقك.

> **معلومة:** النطاقات المخصصة تتطلب **خطة مدفوعة**. فهي تعتمد على منفذ متاح للعامة، والخطط المدفوعة فقط (Bronze وSilver وGold وخطط خوادم الألعاب) تتضمن منافذ عامة. خوادم Free Tier لا تستقبل اتصالات واردة، لذا لا يمكن أن يعمل النطاق المخصص عليها. انظر [خطط استضافة التطبيقات والبوتات](https://daki.cc/ar/wiki/guides/paid-plans) و[تخصيصات الشبكة](https://daki.cc/ar/wiki/guides/network-allocations).

## ما ستتعلمه

- لماذا يحتاج النطاق المخصص على Daki إلى وكيل عكسي مثل Cloudflare
- كيفية توجيه نطاقك إلى خادمك عبر سجل DNS بوكيل
- كيفية تفعيل HTTPS مجانًا لنطاقك
- كيفية توجيه الحركة إلى منفذ تطبيقك عبر Origin Rule
- بديل متقدم باستخدام Cloudflare Tunnel (`cloudflared`)

---

## المتطلبات الأساسية

- خادم **خطة مدفوعة** مع تخصيص شبكة بمنفذ عام — انظر [خطط استضافة التطبيقات والبوتات](https://daki.cc/ar/wiki/guides/paid-plans)
- **اسم نطاق** تملكه (مسجّل لدى أي مسجّل نطاقات، مثل Namecheap أو GoDaddy أو IONOS أو Cloudflare Registrar)
- حساب [Cloudflare](https://dash.cloudflare.com/sign-up) مجاني
- **تطبيق ويب** (HTTP/HTTPS) يعمل ويستمع على تخصيص الشبكة الخاص بخادمك

> **تحذير:** يجب أن يرتبط تطبيقك بـ `0.0.0.0` (كل الواجهات) على منفذ التخصيص — **وليس** `127.0.0.1` / `localhost`. التطبيق المرتبط بـ localhost فقط لا يمكن الوصول إليه من خارج الحاوية، وسيفشل الوكيل في الاتصال به. معظم الأطر تقبل معاملًا للمضيف (مثل `app.run(host="0.0.0.0", port=...)` في Flask، أو `HOST=0.0.0.0` لكثير من تطبيقات Node.js).

---

## لماذا تحتاج إلى Cloudflare

يستخدم Daki **عناوين IP مشتركة** عبر عُقده، ويستمع تطبيقك على **منفذ** غير قياسي (التخصيص المعيّن لخادمك). وينتج عن ذلك مشكلتان:

- يتوقع الزوار الوصول إلى `https://yourdomain.com` عبر منفذ HTTPS القياسي (443) — وليس `yourdomain.com:4129`.
- تريد شهادة HTTPS صالحة دون أن تديرها بنفسك.

وضع Cloudflare أمام خادمك يحل المشكلتين. يعمل Cloudflare كـ **وكيل عكسي**: تتصل المتصفحات بـ Cloudflare عبر HTTPS على المنفذ 443، ويعيد Cloudflare توجيه الطلب إلى خادمك على منفذك المخصص. تحصل على SSL مجاني ورابط نظيف، ويبقى عنوان IP الحقيقي لخادمك مخفيًا.

> **ملاحظة:** تنجح هذه الطريقة مع **تطبيقات الويب HTTP/HTTPS** (المواقع وواجهات API ولوحات التحكم وwebhooks). لا تعمل مع خدمات TCP/UDP الخام مثل معظم خوادم الألعاب، فالوكيل القياسي لـ Cloudflare يتعامل مع HTTP(S) فقط. للخدمات غير HTTP، استخدم طريقة [Cloudflare Tunnel](#advanced-alternative-cloudflare-tunnel-cloudflared) أدناه، أو تواصل مع [الدعم](https://daki.cc/ar/wiki/guides/support).

---

## اعثر على عنوان IP ومنفذ خادمك

تحتاج إلى قيمتين من تبويب **Network** في [Portal](https://daki.cc/ar/wiki/guides/portal):

| القيمة | أين تجدها | مثال |
| :--- | :--- | :--- |
| **عنوان IP للخادم** | عنوان IP الذي يُحل إليه اسم مضيف خادمك (يظهر في تبويب **Network**). إذا ظهر اسم المضيف فقط، فيمكنك حله — مثلًا `ping eu-node1.daki.cc` — أو اسأل [الدعم](https://daki.cc/ar/wiki/guides/support). | `203.0.113.10` |
| **منفذ التخصيص** | المنفذ الظاهر بجانب اسم المضيف في تبويب **Network**. يجب أن يستمع تطبيقك على هذا المنفذ. | `4129` |

سنستخدم هذه القيم كأمثلة طوال الدليل. **استبدلها بقيمك** حيثما وردت. لمزيد من المعلومات عن التخصيصات، انظر [تخصيصات الشبكة](https://daki.cc/ar/wiki/guides/network-allocations).

---

## الجزء 1: إعداد Cloudflare

**الخطوة 1: أضف نطاقك إلى Cloudflare**

1. أنشئ حسابًا مجانيًا على [dash.cloudflare.com](https://dash.cloudflare.com/sign-up) (أو سجّل الدخول).
2. انقر على **Add a site** وأدخل نطاقك (مثل `yourdomain.com`).
3. اختر خطة **Free** عند الطلب.
4. سيمنحك Cloudflare **خادمي أسماء** (nameservers)، مثل `xxx.ns.cloudflare.com`.
5. سجّل الدخول إلى **مسجّل النطاقات** لديك، وابحث عن إعدادات أسماء الخوادم / DNS لنطاقك، واستبدل أسماء الخوادم الحالية بالاثنين اللذين قدّمهما Cloudflare.

> **ملاحظة:** قد تستغرق تغييرات أسماء الخوادم من بضع دقائق حتى 24 ساعة لتنتشر. يرسل لك Cloudflare رسالة بريد إلكتروني عندما يصبح نطاقك نشطًا. يمكنك متابعة الخطوات التالية في الأثناء.

**الخطوة 2: أنشئ سجل DNS**

في لوحة Cloudflare لنطاقك، انتقل إلى **DNS → Records** وانقر على **Add record**:

| الحقل | القيمة |
| :--- | :--- |
| **Type** | `A` |
| **Name** | `@` (يمثل النطاق الجذري `yourdomain.com`) |
| **IPv4 address** | عنوان IP خادمك (مثال: `203.0.113.10`) |
| **Proxy status** | **Proxied** (السحابة البرتقالية ☁️) |

انقر على **Save**.

> **نصيحة:** **السحابة البرتقالية (Proxied)** أساسية، لأنها توجّه الحركة عبر Cloudflare ليعمل SSL وإعادة كتابة المنفذ في الجزء 2. السحابة الرمادية (DNS only) ستتجاوز Cloudflare تمامًا وتكشف عنوان IP خادمك. لتقديم `www.yourdomain.com` أيضًا، أضف سجلًا ثانيًا بوكيل واسمه `www`.

**الخطوة 3: اضبط SSL/TLS**

1. انتقل إلى **SSL/TLS → Overview**.
2. اضبط وضع التشفير على **Flexible**.

**Flexible** يعني أن الحركة بين الزائر وCloudflare مشفّرة (HTTPS)، بينما يتصل Cloudflare بتطبيقك عبر HTTP العادي على منفذك المخصص. هذا هو الخيار المناسب عندما يقدّم تطبيقك HTTP عاديًا، وهذا ما تفعله معظم التطبيقات على منفذ مخصص.

> **ملاحظة:** إذا كان تطبيقك يُنهي TLS بنفسه (أي يقدّم **HTTPS** مباشرة على منفذه)، فاختر **Full** بدلًا من ذلك. انتبه إلى أن **Flexible** لا يشفّر الاتصال بين Cloudflare وخادمك؛ وللحركة الحساسة، فضّل **Full** مع HTTPS في تطبيقك.

---

## الجزء 2: توجيه الحركة إلى منفذ تطبيقك

بما أن تطبيقك يعمل على منفذ مخصص (مثل `4129`) بدلًا من 80/443 القياسية، تحتاج إلى إخبار Cloudflare بالمنفذ الذي يستخدمه عند الاتصال بخادمك. تقوم **Origin Rule** بهذه المهمة بالضبط، إذ تعيد كتابة منفذ الوجهة للطلبات الواردة.

**الخطوة 1: أنشئ Origin Rule**

1. في لوحة Cloudflare، انتقل إلى **Rules → Origin Rules**.
2. انقر على **Create Origin Rule**.
3. اضبط القاعدة:

| الإعداد | القيمة |
| :--- | :--- |
| **When incoming requests match** | Hostname **equals** `yourdomain.com` |
| **Then... Rewrite to** | **Destination Port** → `4129` (منفذ التخصيص الخاص بك) |

4. انقر على **Save** (أو **Deploy**).

> **نجاح:** بمجرد أن ينتشر DNS، يصبح تطبيقك متاحًا على **`https://yourdomain.com`** — يقدّمه Cloudflare عبر HTTPS ويوجّه الحركة إلى خادمك على المنفذ `4129`.

---

## تحقّق من أن كل شيء يعمل

1. تأكد من أن خادمك **يعمل** وأن تطبيقك يستمع على منفذ التخصيص (تحقق من تبويب **Console**).
2. افتح `https://yourdomain.com` في متصفحك.
3. يجب أن ترى تطبيقك يُحمَّل عبر HTTPS مع قفل صالح.

إذا لم يُحمَّل فورًا، أعطِ DNS بعض الوقت لينتشر، ثم انظر إلى [المشكلات الشائعة](#common-issues) أدناه.

---

## بديل متقدم: Cloudflare Tunnel (cloudflared)

بدلًا من فتح منفذ عام والإشارة بسجل A إلى خادمك، يمكنك تشغيل **`cloudflared`** — عميل النفق (tunnel) من Cloudflare — بجانب تطبيقك. يفتح اتصالًا **صادرًا** إلى Cloudflare ويوجّه الحركة إلى تطبيقك محليًا، فيبقى عنوان IP ومنفذ خادمك مخفيين، ولا تحتاج إلى سجل A في DNS ولا إلى Origin Rule.

> **ملاحظة:** **كيف تؤثر بيئة Daki على ذلك.** يمنحك تبويب Startup أمرين — [**أمر التثبيت**](https://daki.cc/ar/wiki/guides/startup-settings) (يعمل مرة واحدة عند الإعداد أو إعادة التثبيت) و**أمر التشغيل** (يعمل عند كل إقلاع) — ويمكنك فتح shell بتغيير أمر التشغيل مؤقتًا إلى `bash`. لكن خادمك **حاوية وليس جهاز Linux كاملًا**: لا يوجد `apt`، ولا يمكنك تسجيل خدمة نظام، والنفق الذي تشغّله يدويًا في الكونسول يتوقف عند إعادة تشغيل الخادم. لذلك فالطريقة الموثوقة هي جعل النفق **جزءًا من بدء تطبيقك نفسه**: تنزيل الملف التنفيذي `cloudflared` وقت التشغيل وتشغيله كعملية فرعية بجانب تطبيقك، يتحكم فيها متغير بيئة.

**الخطوة 1: أنشئ النفق**

1. في لوحة **Zero Trust** الخاصة بـ Cloudflare، انتقل إلى **Networks → Tunnels** وانقر على **Create a tunnel**، ثم اختر **Cloudflared**.
2. أعطه اسمًا، و**انسخ توكن النفق** الذي يعرضه Cloudflare (السلسلة الطويلة بعد `--token` في أمر التثبيت الخاص به).
3. أضف **Public Hostname** إلى النفق:
   - **Domain:** `yourdomain.com`
   - **Service:** `http://localhost:4129` (المنفذ المحلي لتطبيقك)

**الخطوة 2: خزّن التوكن في .env**

أضف التوكن إلى ملف `.env` لخادمك (انظر [متغيرات البيئة](https://daki.cc/ar/wiki/guides/environment-variables)) حتى لا يصل أبدًا إلى كود مصدرك:

```

CLOUDFLARE_TUNNEL_TOKEN=your_tunnel_token_here

```

**الخطوة 3: شغّل النفق من كودك**

أضف مشغّلًا صغيرًا ينزّل `cloudflared` عند أول تشغيل، ويبدأه بجانب تطبيقك، ثم اضبط هذا المشغّل كـ **أمر التشغيل** لديك. لا يبدأ النفق إلا عندما يكون `CLOUDFLARE_TUNNEL_TOKEN` مضبوطًا، لذا يعمل الكود نفسه محليًا دون توكن.

**Node.js (start.js)**

احفظه باسم `start.js`، ثم اضبط أمر التشغيل على `node start.js`:

```js

// start.js — starts your app and, if a token is set, a Cloudflare tunnel.

require("dotenv").config();



const fs = require("fs");

const path = require("path");

const { spawn, spawnSync } = require("child_process");



const CLOUDFLARED_URL =

  "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64";

const binaryPath = path.join(__dirname, "cloudflared");

const children = [];



// The container has no apt — download the binary on first run, reuse it after.

function ensureCloudflared() {

  if (fs.existsSync(binaryPath)) return binaryPath;

  console.log("[tunnel] downloading cloudflared...");

  const dl = spawnSync("curl", ["-fsSL", "-o", binaryPath, CLOUDFLARED_URL], {

    stdio: "inherit",

  });

  if (dl.status !== 0) return null;

  fs.chmodSync(binaryPath, 0o755);

  return binaryPath;

}



// Spawn a child process; if any child exits, stop the rest and quit.

function start(name, command, args) {

  const child = spawn(command, args, { stdio: "inherit", env: process.env });

  child.on("exit", (code) => {

    console.error(`[${name}] exited (${code}); shutting down`);

    for (const c of children) if (!c.killed) c.kill("SIGTERM");

    process.exit(code ?? 1);

  });

  children.push(child);

}



const token = process.env.CLOUDFLARE_TUNNEL_TOKEN?.trim();

if (token) {

  const binary = ensureCloudflared();

  if (binary) start("tunnel", binary, ["tunnel", "run", "--token", token]);

} else {

  console.log("[tunnel] CLOUDFLARE_TUNNEL_TOKEN not set; skipping tunnel");

}



// Start your app — change this to your real entry point.

start("app", "node", ["index.js"]);

```

**Python / أخرى (start.sh)**

احفظه باسم `start.sh`، ثم اضبط أمر التشغيل على `bash start.sh`:

```bash

#!/usr/bin/env bash

# Load variables from .env into the environment.

set -a; [ -f .env ] && . ./.env; set +a



# The container has no apt — download cloudflared on first run, reuse it after.

if [ ! -x ./cloudflared ]; then

  curl -fsSL -o ./cloudflared \

    https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64

  chmod +x ./cloudflared

fi



# Start the tunnel in the background only if a token is set.

if [ -n "$CLOUDFLARE_TUNNEL_TOKEN" ]; then

  ./cloudflared tunnel run --token "$CLOUDFLARE_TUNNEL_TOKEN" &

fi



# Start your app in the foreground — change this to your real command.

exec python main.py

```

> **نصيحة:** لتجنب إعادة التنزيل عند كل إقلاع، يمكنك نقل التنزيل إلى [أمر التثبيت](https://daki.cc/ar/wiki/guides/startup-settings) الخاص بك، والإبقاء على منطق التشغيل فقط في أمر التشغيل. الأمثلة أعلاه آمنة للتشغيل عند كل إقلاع، فهي تتخطى التنزيل بمجرد وجود الملف التنفيذي.

**المقايضات:**

| | وكيل Cloudflare (الجزءان 1–2) | نفق Cloudflare (cloudflared) |
| :--- | :--- | :--- |
| صعوبة الإعداد | أسهل (لوحة التحكم فقط) | أكثر تقدمًا (مدمج في بدء تطبيقك) |
| يكشف IP/المنفذ الخاص بالخادم | مخفي خلف الوكيل | مخفي تمامًا (صادر فقط) |
| يحتاج إلى منفذ عام / Origin Rule | نعم | لا |
| يستهلك موارد الخادم | لا شيء على خادمك | يشغّل عملية إضافية |

---

## المشكلات الشائعة

**الموقع لا يُحمَّل إطلاقًا**

قد لا يزال DNS ينتشر. قد تستغرق تغييرات أسماء الخوادم حتى 24 ساعة (غالبًا أقل بكثير). تأكد في Cloudflare من أن حالة نطاقك **Active** وأن **سجل A** موجود وهو **Proxied** (السحابة البرتقالية). يمكنك التحقق من انتشار DNS بأداة مثل [dnschecker.org](https://dnschecker.org).

**خطأ 522 / 523 — انتهت مهلة الاتصال / الخادم الأصلي غير قابل للوصول**

لا يستطيع Cloudflare الوصول إلى تطبيقك. تحقق بالترتيب:
- أن **خادمك يعمل** وأن التطبيق بدأ بالكامل (تحقق من تبويب **Console**).
- أن **Origin Rule** يعيد كتابة المنفذ إلى **منفذ التخصيص** بالضبط.
- أن **عنوان IP في سجل A** يطابق عنوان IP خادمك.
- أن تطبيقك مرتبط بـ **`0.0.0.0`**، وليس `127.0.0.1` / `localhost`.

**Too many redirects / ERR_TOO_MANY_REDIRECTS**

يكون ذلك عادةً بسبب عدم تطابق وضع SSL. إذا فرض تطبيقك HTTPS بينما يتصل Cloudflare به عبر HTTP، ينتج عن ذلك حلقة إعادة توجيه. إما أن تجعل تطبيقك يقدّم HTTP عاديًا وتستخدم **Flexible**، أو أن يقدّم تطبيقك HTTPS وتغيّر Cloudflare إلى **Full** ضمن **SSL/TLS → Overview**.

**يعمل على http:// ولكن ليس على https://**

تأكد من أن سجل DNS **Proxied** (السحابة البرتقالية) وأن وضع **SSL/TLS** مضبوط (Flexible أو Full). مع السحابة الرمادية (DNS only) يتم تجاوز SSL الخاص بـ Cloudflare.

**خادم ألعابي / خدمة غير HTTP لا تعمل**

وكيل Cloudflare القياسي يتعامل مع HTTP/HTTPS فقط. بالنسبة لخدمات TCP/UDP الخام مثل معظم خوادم الألعاب، لا تنطبق هذه الطريقة. اتصل بخادمك باستخدام اسم مضيفه ومنفذه مباشرةً (انظر [تخصيصات الشبكة](https://daki.cc/ar/wiki/guides/network-allocations))، أو تواصل مع [الدعم](https://daki.cc/ar/wiki/guides/support) بشأن خيارات أخرى.

**هل يجب أن أستخدم Cloudflare؟**

لا. Cloudflare هو أبسط خيار مجاني، لكن أي وكيل عكسي يستطيع التوجيه إلى منفذ مخصص يعمل، مثل نفق عبر `cloudflared`، أو Nginx/Caddy خاص بك أمام التطبيق. يُوصى بـ Cloudflare لأنه يوفر SSL مجانيًا، ويخفي عنوان IP لخادمك، ولا يحتاج إلى برامج إضافية على خادمك في طريقة الوكيل.

---

## الخطوات التالية

- [تخصيصات الشبكة](https://daki.cc/ar/wiki/guides/network-allocations) — ابحث عن اسم مضيفك ومنفذك، وأضف تخصيصات أخرى.
- [خطط استضافة التطبيقات والبوتات](https://daki.cc/ar/wiki/guides/paid-plans) — رقّ إلى خطة مدفوعة للحصول على منفذ عام.
- [متغيرات البيئة](https://daki.cc/ar/wiki/guides/environment-variables) — اقرأ منفذك من متغير بيئة في الكود.
- [الحصول على المساعدة](https://daki.cc/ar/wiki/guides/support) — تواصل مع الدعم إذا علقت.

---
Source: https://daki.cc/ar/wiki/guides/custom-domain
