تطبيق WebRTC لديك يعمل على شبكة Wi-Fi الخاصة بك ويفشل مع ذلك العميل الوحيد الذي يتصل من فندق. تحتاج وسائط الند للند إلى مسار بين الطرفين؛ وحين يكون كلاهما خلف NAT صارم، أو يُسقط جدار حماية حزم UDP، لا يوجد مسار ولا تتصل المكالمة ببساطة. لا يرى أحد أي خطأ — فقط «جارٍ الاتصال…» لا ينتهي.
خادم TURN هو البديل الاحتياطي لهذه المكالمات تحديدًا: يرسل الطرفان وسائطهما إليه، وهو يرحّلها. إن كنت تضيف الفيديو أو الصوت إلى تطبيق، أو تشغّل Matrix أو Jitsi لفريق، أو تبني محادثة صوتية للعبة، فأنت تحتاج إلى واحد. coturn هو التنفيذ القياسي مفتوح المصدر، وهو خفيف.
أي خطة
لا يحتاج TURN إلى كثير من المعالج والذاكرة. ما يستهلكه هو عرض النطاق: يمر كل تدفق مُرحّل عبر الخادم مرتين، دخولًا وخروجًا. حركة البيانات في خططنا غير محدودة بسرعة 1 Gbit/s، فالسؤال هو كم مكالمة مُرحّلة تجري في الوقت نفسه، لا كم ستدفع.
| المكالمات المُرحّلة في الوقت نفسه | الخطة |
|---|---|
| عدد قليل — فريق، تطبيق صغير | Nano-IP: 2 vCPU، 1 GB، 15 GB (8$ شهريًا) |
| عشرات | Micro-IP: 2 vCPU، 2 GB، 25 GB (10$ شهريًا) |
| أكثر، أو TURN بجوار خادم تطبيقك | Small-IP: 4 vCPU، 4 GB، 35 GB (16$ شهريًا) |
يجب أن تكون الخطة بعنوان IPv4 خاص بها — فـ TURN قائم كليًا على الاتصالات الواردة على منافذ كثيرة، وخطط NAT لا تستقبل من الخارج إلا SSH. في خططنا ذات العنوان المخصّص يوجد العنوان العام مباشرة على واجهة الخادم، فيجده coturn دون سطر external-ip. ضع الخادم قريبًا من مستخدميك: ألمانيا أو فنلندا، ويظهر التوفر عند الطلب. الدفع بالعملات المشفّرة دون KYC، إن كان ذلك يهمك.
المنافذ التي يجب فتحها: 3478 عبر UDP وTCP، و49152–65535 عبر UDP للوسائط المُرحّلة، و5349 عبر TCP إن أضفت TLS.
التثبيت والإعداد
بصلاحيات root على Ubuntu 24.04 أو Debian 12:
apt install -y coturn
ip -4 addr # يجب أن يظهر عنوان IP العام على الواجهة
اكتب الإعداد مع سرّ مشترك جديد:
SECRET=$(openssl rand -hex 32)
cat > /etc/turnserver.conf <<EOF
listening-port=3478
fingerprint
use-auth-secret
static-auth-secret=$SECRET
realm=turn.example.com
min-port=49152
max-port=65535
no-cli
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
EOF
echo "$SECRET" # تحتاج الواجهة الخلفية إلى هذه القيمة
systemctl restart coturn
ufw allow 22/tcp && ufw allow 3478 && ufw allow 49152:65535/udp && ufw enable
لا تتجاوز أسطر denied-peer-ip. من دونها يستطيع أي شخص يملك بيانات اعتماد صالحة استخدام مرحّلك للوصول إلى عناوين خاصة — بما في ذلك خدمات على الجانب الداخلي للخادم نفسه. تحققنا من ذلك: مع هذه الأسطر يُرفض الترحيل إلى عنوان خاص بالرسالة «403 Forbidden IP».
بيانات اعتماد تنتهي صلاحيتها
مع use-auth-secret يقبل coturn اسم مستخدم يتضمن وقت انتهاء الصلاحية وكلمة مرور هي HMAC له. يولّدهما خادمك الخلفي؛ ولا يغادر السرّ جانب الخادم أبدًا. في Node.js:
const crypto = require("crypto");
// اسم مستخدم وكلمة مرور مؤقتان لـ TURN (مخطط TURN REST API الذي يفهمه coturn عبر use-auth-secret).
function turnCredentials(secret, user, ttlSeconds = 3600) {
const username = `${Math.floor(Date.now() / 1000) + ttlSeconds}:${user}`;
const credential = crypto.createHmac("sha1", secret).update(username).digest("base64");
return { username, credential };
}
console.log(JSON.stringify(turnCredentials(process.env.TURN_SECRET, "alice")));
في المتصفح، اطلب من خادمك الخلفي زوجًا جديدًا ومرّره إلى RTCPeerConnection:
const { username, credential } = await fetch("/api/turn-credentials").then((r) => r.json());
const pc = new RTCPeerConnection({
iceServers: [
{ urls: "stun:turn.example.com:3478" },
{
urls: ["turn:turn.example.com:3478?transport=udp", "turn:turn.example.com:3478?transport=tcp"],
username,
credential,
},
],
});
اختبره
من الخادم، بالمخطط نفسه عبر openssl (يُنتج كلمة المرور نفسها تمامًا التي يُنتجها كود Node.js — قارنّا):
U="$(( $(date +%s) + 3600 )):test"
P=$(echo -n "$U" | openssl dgst -binary -sha1 -hmac "$SECRET" | base64)
turnutils_uclient -y -n 10 -u "$U" -w "$P" YOUR_SERVER_IP
في النهاية تريد أن ترى «Total lost packets 0». مع كلمة مرور خاطئة يتوقف العميل عند «Cannot complete Allocation» — وهذا هو الخادم يؤدي عمله.
تحققنا أيضًا من Chromium حقيقي: مع iceTransportPolicy: "relay" وبيانات اعتماد جديدة حصل المتصفح على مرشحي relay من الخادم؛ ومع كلمة مرور سيئة لم يحصل على أي منها. إن أردت اختبار إعدادك بالطريقة نفسها، ففعّل هذا الخيار للحظة — فهو يجبر كل مكالمة على المرور عبر TURN.
TLS عند الحاجة
بعض الشبكات تحجب UDP وتتشدد مع TCP العادي؛ وTURN عبر TLS يمر من عدد أكبر منها. احصل على شهادة لـ turn.example.com (يكفي certbot). لا يستطيع قراءة ملفاتها إلا root، بينما يعمل coturn بالمستخدم turnserver، لذا امنح coturn نسخة خاصة به:
mkdir -p /etc/coturn
cp /etc/letsencrypt/live/turn.example.com/fullchain.pem /etc/letsencrypt/live/turn.example.com/privkey.pem /etc/coturn/
chown turnserver: /etc/coturn/*.pem && chmod 640 /etc/coturn/privkey.pem
cat >> /etc/turnserver.conf <<'EOF'
tls-listening-port=5349
cert=/etc/coturn/fullchain.pem
pkey=/etc/coturn/privkey.pem
EOF
systemctl restart coturn && ufw allow 5349/tcp
أضف turns:turn.example.com:5349?transport=tcp إلى قائمة urls. الشهادات قصيرة العمر، فضع عملية النسخ في deploy hook الخاص بـ certbot — وإلا تعطل TLS بصمت عند أول تجديد.
يجدر معرفته
- لا يجعل TURN الاتصال السيئ جيدًا. فهو يضيف قفزة واحدة، لذا ضع الخادم قرب من يحتاجون إليه.
- إن كنت تشغّل SFU — مثل videobridge في Jitsi — فهذه قطعة منفصلة. يساعد TURN العملاء الذين لا يستطيعون الوصول إليها مباشرة.
- السرّ هو نموذج الأمان كله. أبقِه خارج الواجهة الأمامية، وغيّره إن تسرّب يومًا.
ذو صلة
- خادم VPS لـ Jitsi Meet: مكالمات فيديو على خادمك
- استضف Matrix Synapse بنفسك: مكالمات Matrix تحتاج أيضًا إلى خادم TURN
- خادم VPS لموقع ويب بعنوان IP خاص: التطبيق الذي يوزّع بيانات الاعتماد
- كيف تضبط جدار الحماية ufw
التعليقات
لا تعليقات بعد. كن الأول.