استضافة بوت ديسكورد على VPS: أبقِه متصلاً 24/7
- ١٨ أكتوبر ٢٠٢٦
- ٠٩:٠٠ ص
- بقلم Adrien Roche
- دروس

لماذا يبقى بوت ديسكورد متصلاً فعلاً على خادم VPS
بوت ديسكورد ليس صفحة ويب. فبمجرد تسجيل الدخول يحافظ على اتصال WebSocket دائم ببوابة ديسكورد ويجب أن يردّ على نبضات الاتصال باستمرار؛ وحين تتوقف العملية يظهر البوت خارج الاتصال وتفشل كل الأوامر. هذا الشرط وحده، أي عملية لا تنام أبداً، يستبعد معظم الاستضافات «المجانية»:
- Heroku ألغت خطط dynos المجانية في نوفمبر 2022.
- Replit لم تعد تُبقي المشاريع المجانية قيد التشغيل؛ وانتقلت ميزة always-on إلى عمليات النشر المدفوعة.
- Glitch أنهت استضافة التطبيقات لديها في 2025.
- الخطط المجانية التي تنام بعد فترة خمول تقطع اتصال البوابة في كل مرة تتوقف فيها؛ وبالنسبة للمستخدمين يكون البوت ببساطة معطلاً.
استضافة بوت ديسكورد على خادم VPS تعالج المشكلة من جذرها: جهاز Linux بصلاحيات root يعمل على مدار الساعة، حيث يصبح البوت مجرد خدمة أخرى يديرها نظام التشغيل الأولي. يبني هذا الدليل ذلك على Ubuntu 24.04 (صالح كذلك لـ 22.04 وDebian 12) باستخدام discord.py وdiscord.js، ثم يتناول التعامل مع التوكن وإعادة التشغيل والسجلات والتحديثات والذاكرة.
تجهيز الخادم: مستخدم مخصص وبيئة تشغيل
أمّن الباب الأمامي أولاً: فعّل SSH على Ubuntu وقوّه بالمصادقة بالمفاتيح، ومنع دخول root، وufw. البوت يتصل خارجياً بديسكورد ولا يحتاج أي منفذ وارد، لذا يمكن أن يبقى الجدار الناري مغلقاً أمام كل شيء عدا SSH.
الخطوة 1: أنشئ حساباً بلا صلاحيات للبوت
sudo useradd -r -m -d /opt/mybot -s /usr/sbin/nologin bot
الحساب المخصص يعني أن بوتاً به خلل أو اعتمادية مخترقة من npm أو PyPI لن تستطيع قراءة مفاتيح SSH أو المساس بخدمات أخرى. كل شيء موجود في /opt/mybot، والمالك هو bot.
الخطوة 2 (Python): ثبّت discord.py في بيئة افتراضية
sudo apt update && sudo apt install -y python3 python3-venv python3-pip
sudo -u bot python3 -m venv /opt/mybot/.venv
sudo -u bot /opt/mybot/.venv/bin/pip install -U discord.py python-dotenv
يتطلب discord.py 2.x إصدار Python 3.8 أو أحدث؛ ويأتي Ubuntu 24.04 بالإصدار 3.12 و22.04 بالإصدار 3.10، لذا فإن مفسّر التوزيعة مناسب. أضف discord.py[voice] وffmpeg فقط إذا كنت تستخدم القنوات الصوتية.
الخطوة 3 (Node.js): ثبّت إصدار LTS حديثاً وdiscord.js
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
sudo -u bot bash -c 'cd /opt/mybot && npm init -y && npm install discord.js dotenv'
حزمة nodejs في Ubuntu متأخرة كثيراً عن الإصدار الأصلي، وdiscord.js v14 يحتاج بيئة تشغيل حديثة، لذا استخدم NodeSource (أعلاه) أو nvm للحصول على LTS حديث. مع nvm، شغّل which node واستخدم ذلك المسار المطلق في ملف الخدمة.
أبقِ التوكن خارج الكود: ملف .env
توكن البوت كلمة مرور تمنح تحكماً كاملاً به: لا تلصقه أبداً في bot.py أو index.js، ولا ترفعه إلى المستودع. ضعه في /opt/mybot/.env بحيث يقرأه حساب البوت وحده، واستخدم محرراً بدل echo، لأن أي توكن يُكتب في سطر الأوامر ينتهي في سجل الأوامر لديك:
sudo -u bot nano /opt/mybot/.env # one line: DISCORD_TOKEN=your-token-here
sudo chmod 600 /opt/mybot/.env
echo ".env" | sudo -u bot tee -a /opt/mybot/.gitignore
الصيغة هي KEY=value واحد في كل سطر، بلا علامات اقتباس وبلا export. يقرؤه python-dotenv وحزمة dotenv في npm، ويستطيع systemd حقن الملف نفسه عبر EnvironmentFile= (القسم التالي)؛ والجمع بينهما غير ضار، لأن أياً من المكتبتين لا يتجاوز متغيراً موجوداً أصلاً. وإذا تسرّب التوكن يوماً، أعد تعيينه فوراً في Developer Portal ضمن Bot → Reset Token.
بوت بسيط في discord.py وdiscord.js
يقرأ المثالان التوكن من البيئة، ويفعّلان صلاحية Message Content، ويردّان على !ping. في Developer Portal، أنشئ تطبيقاً، وأضف مستخدم بوت، وانسخ التوكن (يُعرض مرة واحدة)، وفعّل Message Content Intent ضمن Bot → Privileged Gateway Intents، ثم ادعُ البوت إلى خادم تجريبي عبر مولّد روابط OAuth2 مع نطاق bot.
discord.py: /opt/mybot/bot.py
import os
import discord
from dotenv import load_dotenv
load_dotenv()
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
@client.event
async def on_ready():
print(f"Logged in as {client.user}")
@client.event
async def on_message(message):
if message.author == client.user:
return
if message.content == "!ping":
await message.channel.send("pong")
client.run(os.environ["DISCORD_TOKEN"])
discord.js: /opt/mybot/index.js
require("dotenv").config();
const { Client, GatewayIntentBits, Events } = require("discord.js");
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
client.once(Events.ClientReady, (c) => {
console.log(`Logged in as ${c.user.tag}`);
});
client.on(Events.MessageCreate, (message) => {
if (message.author.bot) return;
if (message.content === "!ping") message.reply("pong");
});
client.login(process.env.DISCORD_TOKEN);
شغّله في المقدمة مرة واحدة: sudo -u bot /opt/mybot/.venv/bin/python /opt/mybot/bot.py أو sudo -u bot node /opt/mybot/index.js، وانتظر ظهور Logged in as، وأرسل !ping، ثم اضغط Ctrl-C. في هذه اللحظة يعيش البوت بقدر ما تعيش جلسة SSH فقط: إغلاق الطرفية يرسل SIGHUP إلى العمليات الفرعية فيموت البوت.
شغّله عبر systemd مع Restart=always
systemd هو أصلاً نظام التشغيل الأولي في Ubuntu، لذا فإن أنظف طريقة لإبقاء البوت متصلاً بعد الخروج والعطل وإعادة التشغيل هي وحدة خدمة: بلا خدمة إضافية، ومع سجلات تصل إلى journal.
الخطوة 1: اكتب الوحدة
sudo nano /etc/systemd/system/mybot.service
[Unit]
Description=Discord bot
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=bot
Group=bot
WorkingDirectory=/opt/mybot
EnvironmentFile=/opt/mybot/.env
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/mybot/.venv/bin/python /opt/mybot/bot.py
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/mybot
[Install]
WantedBy=multi-user.target
لـ discord.js، اضبط ExecStart=/usr/bin/node /opt/mybot/index.js واحذف سطر PYTHONUNBUFFERED. أما التوجيهات المهمة فهي:
Restart=alwaysيعيد تشغيل العملية عند أي خروج، سواء كان عطلاً أوsys.exit()نظيفاً؛ وRestartSec=5يمنع بوتاً يموت فوراً (توكن خاطئ، خطأ نحوي) من الدوران في حلقة سريعة.Wants=/After=network-online.targetيؤخران البدء حتى تعمل الشبكة، فلا يفشل أول تسجيل دخول بعد إعادة التشغيل بسبب DNS.PYTHONUNBUFFERED=1: بدون طرفية يخزّن Python مخرجاتstdoutعلى شكل كتل، فتصل أسطرprint()إلى journal متأخرة بدقائق أو عند الخروج فقط.- أسطر
Protect*وPrivateTmpوNoNewPrivilegesتجعل بقية نظام الملفات للقراءة فقط أو غير مرئية للبوت؛ أضف أي مجلد يحتاج الكتابة فيه إلىReadWritePaths=.
الخطوة 2: التفعيل والتشغيل والتحقق
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
systemctl status mybot
sudo systemctl kill --signal=KILL mybot # simulate a crash; status is active again after 5 s
enable ينشئ الرابط الرمزي الخاص بالإقلاع و--now يبدأ الوحدة. وسطر kill هو الاختبار الحقيقي: إذا أظهر systemctl status mybot حالة active (running) بعد ثوانٍ قليلة، فسياسة إعادة التشغيل تعمل، وsudo reboot يثبت صحة مسار الإقلاع. ولرؤيتها إلى جانب بقية الخدمات، اعرض الخدمات العاملة عبر systemctl؛ ستظهر باسم mybot.service، ويؤكد systemctl is-enabled mybot أنها ستعود بعد إعادة التشغيل.
البديل: pm2، ومقارنته بـ screen وnohup وDocker
كل طريقة لإبقاء البوت حياً تجيب عن ثلاثة أسئلة: هل تنجو من الخروج من SSH، وهل تعيد التشغيل عند العطل، وهل تبدأ عند الإقلاع؟
| الطريقة | تنجو من الخروج من SSH | تعيد التشغيل عند العطل | تبدأ عند الإقلاع | الخلاصة |
|---|---|---|---|---|
nohup / & | نعم | لا | لا | للاختبارات السريعة فقط. |
screen / tmux | نعم | لا | لا، إلا عبر سكربت | لتصحيح الأخطاء، لا للإنتاج. |
| pm2 | نعم | نعم | نعم، بعد pm2 startup + pm2 save | مناسبة لفرق Node.js؛ واجهة أوامر واحدة للسجلات وإعادة التشغيل. |
| وحدة systemd | نعم | نعم (Restart=) | نعم (enable) | الخيار المُوصى به؛ بلا برامج إضافية، مع تقوية أمنية مدمجة. |
Docker، restart: unless-stopped | نعم | نعم | نعم، مع خدمة Docker | مناسب حين يُشحن البوت أصلاً كصورة. |
pm2 هو الخيار الشائع في عالم Node.js ويتعامل مع Python أيضاً. شغّله بالحساب الذي يملك البوت:
sudo npm install -g pm2
cd /opt/mybot
pm2 start index.js --name mybot
pm2 start bot.py --name mybot --interpreter /opt/mybot/.venv/bin/python # Python variant
pm2 save
pm2 startup # prints a sudo command to run once
pm2 logs mybot
pm2 install pm2-logrotate # ~/.pm2/logs/ otherwise grows forever
ينشئ pm2 startup وحدة systemd باسم pm2-<user> تُحيي قائمة العمليات المحفوظة عند الإقلاع، أي أن pm2 يجلس فوق systemd بدل أن يحل محله: وهذه هي الحجة الصادقة لاستخدام systemd مباشرة مع بوت واحد. أما pm2 فيستحق مكانه مع عدة عمليات Node أو فريق يعرفه مسبقاً.
إذا كنت تفضّل الحاويات، فالمكافئ هو restart: unless-stopped في ملف Compose؛ ويغطي دليل تثبيت Docker على خادم Ubuntu VPS المحرك وCompose وسلوك الإقلاع. أما تحفّظه بشأن ufw فلا يؤثر على بوت لا ينشر أي منافذ.
السجلات والتحديثات وحجم الذاكرة
السجلات
journalctl -u mybot -f # follow live
journalctl -u mybot --since "1 hour ago"
journalctl -u mybot -p err -b # errors since boot
sudo journalctl --vacuum-size=200M # cap journal size
يتولى journald التدوير والضغط تلقائياً. وإذا كان البوت يكتب ملف سجل خاصاً به، استخدم logging.handlers.RotatingFileHandler في Python أو ناقلاً دوّاراً مع pino أو winston في Node، حتى لا يملأ معالج ثرثار القرص.
التحديثات
cd /opt/mybot
sudo -u bot git pull
sudo -u bot .venv/bin/pip install -U -r requirements.txt # Node: sudo -u bot npm ci
sudo systemctl restart mybot
إعادة التشغيل تقطع اتصال البوابة لبضع ثوانٍ؛ فتعيد المكتبة الاتصال ونادراً ما يلاحظ المستخدمون ذلك. ثبّت إصدارات المكتبات في requirements.txt أو package-lock.json واقرأ سجل التغييرات قبل أي ترقية كبرى. وأبقِ نظام التشغيل محدثاً عبر sudo apt update && sudo apt upgrade أو unattended-upgrades.
كم يحتاج البوت من الذاكرة؟
لا تحدد الحجم بأرقام عامة؛ بل قِس. يطبع systemctl status mybot سطر Memory: ويعرض pm2 list الشيء نفسه. بوت discord.py يقتصر على الأوامر يستهلك عادة عشرات الميغابايتات في وضع الخمول؛ أما بوت discord.js فيحمل بيئة تشغيل Node فوق ذلك. وتنمو الذاكرة مع الحالة: ذاكرة الأعضاء والرسائل المؤقتة في الخوادم الكبيرة، والصوت والموسيقى (عملية ffmpeg لكل بث)، وتوليد الصور أو قاعدة بيانات. عملياً، 1 غيغابايت من الذاكرة تشغّل نظام التشغيل وبوتاً صغيراً أو متوسطاً براحة؛ أما البوتات كثيفة الصوت أو تشغيل عدة بوتات على جهاز واحد فتبرر 2 غيغابايت أو أكثر، وفوق 2500 خادم يفرض ديسكورد التجزئة (sharding) التي تضاعف الاستهلاك. وهناك شبكتا أمان رخيصتان: MemoryMax=512M في الوحدة، حتى يعيد تسرّب الذاكرة تشغيل البوت بدل إسقاط الجهاز، وملف swap صغير.
كل هذا يفترض جهاز Linux بصلاحيات root يعمل على مدار الساعة. وإذا كنت لا تزال تحتاج ذلك الجهاز، فإن خادم VPS لبوتات ديسكورد من rdp.monster يصبح متصلاً بعد نحو 10 ثوانٍ من تأكيد الدفع، مع معالج وذاكرة مخصصين، وصلاحيات root كاملة، ونطاق ترددي غير محدود (ضمن الاستخدام العادل)، دون KYC، مع قبول العملات المشفرة، ابتداءً من 8.99 دولار شهرياً، بحيث تكون خطوة systemctl enable --now mybot أعلاه آخر ما تكتبه قبل أن يظهر البوت باللون الأخضر.
الأسئلة الشائعة
هل يمكنني استضافة بوت ديسكورد مجاناً على مدار الساعة؟
systemd تشغيل البوت عند العطل وعند الإقلاع ولا يوقفه أحد بسبب الخمول.هل يحتاج بوت ديسكورد إلى IP ثابت أو منافذ مفتوحة على الخادم؟
هل يمكنني تشغيل عدة بوتات ديسكورد على خادم VPS واحد؟
/opt/bot-a و/opt/bot-b، وملف .env خاصاً بتوكنه، وملف وحدة خاصاً به، ثم نفّذ systemctl enable --now لكل واحد. ويمنع فصل مستخدمي النظام خللاً في بوت من قراءة توكن الآخر. والميزانية المشتركة الوحيدة هي الذاكرة والمعالج: راقب systemctl status لكل وحدة، وانتقل إلى خطة أكبر حين يقترب المجموع من الحد.هل أستضيف بوت ديسكورد على خادم Windows أم Linux؟
systemd من عشرة أسطر. وعلى Windows ستستخدم Task Scheduler أو NSSM للحصول على السلوك نفسه عند الإقلاع مع نقرات أكثر.Adrien Roche, محرر البنية التحتية والاستضافة
مهندس أنظمة بخبرة تزيد عن 10 سنوات في تشغيل أساطيل Windows Server وLinux. يدير أدريان وثائق البنية التحتية في rdp.monster ويكتب أدلتنا حول RDP واستضافة VPS وإدارة الخوادم والشبكات وأدوات الخصوصية.




