SSD Nodes Learn
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-07-22

استضف Rocket.Chat ذاتيًا عبر Docker Compose

استضف Rocket.Chat ذاتيًا على VPS عبر Docker Compose: مجموعة نسخ MongoDB المتماثلة أحادية العقدة المطلوبة، وTLS، والنسخ الاحتياطي، وحلول لكل عطل محتمل.

ما الذي تبنيه

محادثة فريق خاصة تملكها بالكامل: يعمل Rocket.Chat على خادم VPS الخاص بك عبر Docker Compose، خلف طبقة TLS، وكل رسالة تستقر في قاعدة بيانات MongoDB يمكنك نسخها احتياطيًا ونقلها. Rocket.Chat هو البديل الناضج مفتوح المصدر لـ Slack وTeams: قنوات، ورسائل مباشرة، وخيوط نقاش (threads)، ومشاركة ملفات، وصوت وفيديو، كل ذلك على عتاد تستأجره وتتحكم فيه بنفسك. التطبيق حاوية واحدة تُقلِع خلال دقائق. أما كل ما يمكن أن يسوء فعليًا فيسكن في قاعدة البيانات المجاورة له، ولذلك يتناول معظم هذا الدليل MongoDB، وبخاصة المتطلب الوحيد الذي يفاجئ الجميع أول مرة: Rocket.Chat لا يعمل مع MongoDB مستقل قائم بذاته. فهو يحتاج إلى مجموعة نسخ متماثلة (replica set)، حتى لو كانت هذه «المجموعة» عقدة واحدة فقط.

المتطلبات المسبقة، وحساب RAM الذي لا يخبرك به أحد

قدِّر سعة الخادم بواقعية. الحد الأدنى الواقعي لفريق صغير هو 2 vCPU و4 GB من ذاكرة RAM. تحتاج عملية Node.js الخاصة بـ Rocket.Chat وحدها إلى نحو 1 إلى 1.5 GB، بينما تستحوذ ذاكرة WiredTiger المؤقتة الخاصة بـ MongoDB افتراضيًا على نحو نصف ما تبقى من RAM. على خادم VPS بسعة 2 GB تتّسع لهما الذاكرة معًا عند الإقلاع، ثم يتصادمان في اللحظة التي تصل فيها حركة مرور حقيقية: MongoDB يوسّع ذاكرته المؤقتة، وNode يوسّع كومته (heap)، وتنفد صفحات النواة، فيطلق قاتل نفاد الذاكرة (out-of-memory killer) النار على أكبر عملية — وعادة ما تكون mongod. تطبع الحاوية Killed، ويعيد Docker تشغيلها، فتحصل على خادم دردشة يتعطل كل بضع دقائق تحت حمل كان يُفترض أن يتحمّله دون مشقة. 2 GB تكفي لتجربة النظام مع شخصين؛ لكنها ليست خادم فريق. ابدأ بـ 4 GB، وامنحه 8 GB إن كنت تتوقع عشرات المستخدمين المتزامنين، أو مكالمات فيديو، أو سجل تحميلات متزايد.

تحتاج أيضًا إلى ثلاثة أمور جاهزة قبل أن تبدأ. اسم نطاق (domain) يحمل سجل A يشير إلى عنوان IP العام للخادم — إذ تحتاج ميزات Rocket.Chat اللحظية وتطبيقات الجوال إلى اسم مضيف (hostname) ثابت، لا عنوان IP مجردًا فحسب. وفتح المنفذين 80 و443 على كل من جدار حماية الخادم وجدار الحماية الشبكي لدى مزوّد الخدمة، وهو ضبط منفصل في معظم لوحات التحكم. وخادم VPS جديد بنظام Ubuntu 24.04 من نوع KVM مع صلاحيات root أو sudo. وإن كنت ما زلت تحدد ما إذا كان خادم دردشة هو الخدمة الأولى المناسبة لتشغيلها، فإن دليل ما يستحق الاستضافة الذاتية في 2026 يوضح المفاضلات.

ثبّت محرك Docker وإضافة Compose

استخدم مستودع apt الخاص بـ Docker نفسه، لا حزمة docker.io التي توزّعها Ubuntu، ولا الملف التنفيذي القديم القائم بذاته docker-compose المكتوب بلغة Python. Compose الحديث إضافة (plugin) لـ Docker تستدعيها بالأمر docker compose — بمسافة، لا بشرطة. أما docker-compose من الإصدار v1 القديم فهو منتهي الصيانة (end-of-life) ويسيء التعامل مع صياغة الفحص الصحي (healthcheck) والتبعيات (dependency) الموضحة أدناه.

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

تأكد من وجود الجزأين معًا:

sudo docker version
sudo docker compose version

الفحص المهم هو أن يطبع الأمر docker compose version شيئًا يشبه Docker Compose version v2.x. وإذا ظهر الخطأ docker: 'compose' is not a docker command، فإن الإضافة لم تُثبَّت، وأنت مقبل على أعطال محيّرة لاحقًا — أصلح ذلك الآن.

ملف compose: MongoDB كمجموعة نسخ متماثلة بعقدة واحدة

هذا هو الجزء الذي يخطئ فيه الناس، فاقرأه ببطء. يستخدم Rocket.Chat تدفقات التغيير (change streams) الخاصة بـ MongoDB لدفع الرسائل الجديدة إلى العملاء المتصلين في الوقت الفعلي، وتدفقات التغيير هذه لا تتوفر إلا على مجموعة نسخ متماثلة. وجِّه Rocket.Chat إلى mongod مستقل قائم بذاته وسيتصل، لكنه سيفشل في فتح تدفق تغيير، ويدخل في حلقة إعادة تشغيل لا تنتهي. الحل ليس غريبًا: تشغّل حاوية MongoDB واحدة عادية، لكن تبدأها بالخيار --replSet ثم تهيّئ مجموعة بعضو واحد فقط.

أنشئ دليل عمل وملف compose.yml:

services:
  mongodb:
    image: mongo:8.0
    restart: always
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--oplogSize", "128"]
    volumes:
      - mongodb_data:/data/db
      - mongodb_config:/data/configdb
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 10s
      retries: 12

  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:8.5.1
    restart: always
    depends_on:
      mongodb:
        condition: service_healthy
    environment:
      MONGO_URL: "mongodb://mongodb:27017/rocketchat?replicaSet=rs0"
      MONGO_OPLOG_URL: "mongodb://mongodb:27017/local?replicaSet=rs0"
      ROOT_URL: "https://chat.example.com"
      PORT: "3000"
    ports:
      - "127.0.0.1:3000:3000"

volumes:
  mongodb_data:
  mongodb_config:

بعض الخيارات هنا متعمّدة. مَنفذ Rocket.Chat يُنشَر على 127.0.0.1:3000، لا على 0.0.0.0 — فالتطبيق نفسه لا يملك TLS، لذا ينبغي ألا يصل إليه سوى الوكيل العكسي (reverse proxy) على الجهاز نفسه؛ وربطه بكل الواجهات كان سيضع صفحة تسجيل دخول نصية غير مشفّرة مباشرة على الإنترنت العام. أما MongoDB فلا يُنشَر على المضيف إطلاقًا؛ ولا يمكن الوصول إليه إلا عبر شبكة Compose الداخلية تحت الاسم mongodb، وهو بالضبط اسم المضيف الذي يستخدمه MONGO_URL. يحمل MONGO_URL المقطع ?replicaSet=rs0 — احذفه وسيتعامل برنامج التشغيل (driver) مع الخادم كأنه مستقل حتى لو كان مجموعة نسخ متماثلة، فتفشل تدفقات التغيير رغم ذلك. أما MONGO_OPLOG_URL فيشير إلى قاعدة البيانات local حيث يقيم الـ oplog؛ ونسخة Rocket.Chat الحديثة تفضّل تدفقات التغيير، لكن ضبط هذا المتغيّر غير ضار ويُبقي التوافق مع مسارات الشيفرة القديمة قائمًا. أما depends_on فيستخدم condition: service_healthy، لذا ينتظر Compose حتى يستجيب MongoDB لأمر ping قبل أن يبدأ حتى تشغيل Rocket.Chat — وهذا ما يُستخدم الفحص الصحي من أجله.

ثبّت وسوم إصدار حقيقية على كلتا الصورتين — mongo:8.0 وإصدار Rocket.Chat صريح مثل 8.5.1 هنا — ولا تستخدم أبدًا :latest، الذي يحوّل أمر docker pull غير المراقَب إلى ترقية عرضية يتعذر التراجع عنها. تحقق من إصدار Rocket.Chat المستقر الحالي وإصدارات MongoDB التي يدعمها قبل أن تثبّت الوسوم. ينشر Rocket.Chat وثيقة معلومات قابلة للقراءة آليًا مع كل إصدار: يعيد الأمر curl -s https://releases.rocket.chat/8.5.1/info | jq '{compatibleMongoVersions, lts}' القيمة compatibleMongoVersions: ["8.0"] للإصدار 8.5.1، لذا فإن mongo:8.0 هو المحرك الوحيد المدعوم، إضافة إلى علامة lts تخبرك إن كان هذا الإصدار بناء دعم طويل الأمد (long-term support) يستحق التثبيت لخادم تفضّل ألا تراقبه باستمرار.

هيّئ مجموعة النسخ المتماثلة

شغّل الحزمة (stack):

sudo docker compose up -d

سيبدأ Rocket.Chat في الانهيار فورًا وسيواصل Docker إعادة تشغيله — وهذا متوقع، لأن مجموعة النسخ المتماثلة غير موجودة بعد. أنشئها مرة واحدة، يدويًا:

sudo docker compose exec mongodb mongosh --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "mongodb:27017"}]})'

النتيجة الصحيحة هي { ok: 1 }. خلال ثوانٍ قليلة تنتخب العقدة الوحيدة نفسها عقدة أساسية (primary)؛ تأكد من ذلك بالأمر:

sudo docker compose exec mongodb mongosh --quiet --eval 'rs.status().members[0].stateStr'

ما تريد رؤيته هو PRIMARY. أهم تفصيل على الإطلاق في هذه الصفحة كلها هو المعطى host: "mongodb:27017". فإن نفّذت rs.initiate() مجردة بلا قائمة أعضاء، سيُعلن MongoDB عن مجموعة النسخ المتماثلة تحت اسم المضيف الداخلي للحاوية — تجزئة (hash) عشوائية مثل a1b2c3d4e5f6. ولأن Rocket.Chat يتصل من حاويته الخاصة، فلن يستطيع حلّ هذا الاسم، فيفشل برنامج تشغيل MongoDB في حلّه عبر DNS ويدور في حلقة لا نهائية مسجّلًا MongoServerSelectionError: getaddrinfo ENOTFOUND a1b2c3d4e5f6. بادر دائمًا بالتهيئة باسم الخدمة الصريح الذي يطابق MONGO_URL لديك.

الإقلاع الأول: راقبه وهو يعمل

بمجرد أن تصبح المجموعة أساسية، يتصل Rocket.Chat بنظافة عند إعادة تشغيله التالية ويبدأ ترحيلات (migrations) أول تشغيل. تابع السجلّات:

sudo docker compose logs -f rocketchat

السطر الذي تنتظره هو رسالة بدء التشغيل:

+--------------------------------------------+
        SERVER RUNNING
   Rocket.Chat Version: 8.5.1
        NodeJS Version: 22.22.3 - x64
+--------------------------------------------+

الإقلاع الأول بطيء — إذ يشغّل التطبيق ترحيلات قاعدة بيانات ويبني فهارس (indexes)، فأمهله دقيقة أو دقيقتين قبل أن تقلق. أما إن كرّر السجل بدلًا من ذلك MongoServerSelectionError: Server selection timed out after 30000 ms مع وصف طوبولوجيا من نوع ReplicaSetNoPrimary، فمجموعة النسخ المتماثلة لم تُهيَّأ بعد؛ وإن كرّر getaddrinfo ENOTFOUND مع تجزئة عشوائية، فقد هُيِّئت بالمضيف الخاطئ. في الحالتين، ارجع خطوة إلى الوراء. وبمجرد أن ترى SERVER RUNNING، يكون Rocket.Chat يستمع على 127.0.0.1:3000 وقد حان وقت وضع اسم مضيف حقيقي وTLS أمامه.

ضعه خلف TLS

لا تعرِّض Rocket.Chat أبدًا عبر HTTP العادي. سجّل الدخول مرة واحدة عبر http:// وتكون قد سلّمت كلمة مرور المشرف لأي شخص يتنصت على الاتصال بينكما. أنهِ TLS في وكيل عكسي على الجهاز نفسه ووجّهه إلى 127.0.0.1:3000. أمران مهمان هنا: يجب أن يمرّر الوكيل ترويسات ترقية WebSocket (upgrade headers)، لأن Rocket.Chat يعمل في الوقت الفعلي ويتعطل من دونها، ويجب أن يطابق ROOT_URL الخاص بالحاوية تمامًا العنوان العام HTTPS الذي يكتبه المستخدمون.

ابدأ بكتلة خادم nginx بسيطة على HTTP توجّه الطلبات إلى التطبيق وتمرّر ترويسات الترقية. احفظها باسم /etc/nginx/sites-available/rocketchat، واربطها رمزيًا (symlink) داخل sites-enabled، ثم أعد التحميل:

server {
    listen 80;
    server_name chat.example.com;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

اتركها على المنفذ 80 الآن — فكتلة تحمل listen 443 ssl; بلا شهادة لن تجتاز حتى فحص sudo nginx -t. أعد تحميل nginx (sudo nginx -t && sudo systemctl reload nginx)، ثم أصدر الشهادة. أنظف طريق على Ubuntu هو شهادات TLS من Let's Encrypt عبر Certbot وnginx: يعيد الأمر certbot --nginx كتابة الكتلة أعلاه في مكانها، مضيفًا listen 443 ssl;، وسطور ssl_certificate، وإعادة توجيه تلقائية من 80 إلى 443، ويجدول التجديد نيابة عنك. وإن كنت تشغّل بالفعل عدة حاويات خلف وكيل واحد، فإن Traefik مع TLS تلقائي لتطبيقات Docker المتعددة هو الخيار الأنظف — أضف بطاقات (labels) الموجّه والخدمة إلى خدمة rocketchat وسيطلب Traefik الشهادة ويجدّدها نيابة عنك، من دون أي كتلة nginx إطلاقًا. وفي الحالتين، اضبط ROOT_URL على https://chat.example.com في compose.yml وأعد تنفيذ sudo docker compose up -d ليأخذ الحاوية التغيير في الحسبان. وإن أردت أن يكون الخادم قابلًا للوصول فقط من داخل شبكتك الخاصة لا من الإنترنت العام، فضع أمامه شبكة WireGuard VPN مستضافة ذاتيًا على الـ VPS واربط الوكيل بعنوان النفق (tunnel).

معالج الإعداد عند التشغيل الأول

افتح https://chat.example.com وسيرشدك Rocket.Chat عبر معالج قصير. أولًا، حساب المشرف — اسم حقيقي، واسم مستخدم، وبريد إلكتروني، وكلمة مرور قوية؛ وهذا هو الحساب الوحيد الموجود، فلا تفقده. بعد ذلك، معلومات المؤسسة والخادم — الاسم، والقطاع، والحجم، واسم الموقع، واللغة الافتراضية؛ وهذه تفصيلات شكلية، فاملأها وتابع. ثم يأتي الخيار الذي يهم فعلًا: تسجيل مساحة العمل هذه لدى Rocket.Chat Cloud، أو إبقاؤها مستقلة (standalone).

التسجيل يفعّل الإشعارات الفورية (push notifications) على الجوال عبر بوابة Rocket.Chat وسوق الإضافات (add-ons)، على حساب إقامة علاقة مستوى تحكم (control plane) مع سحابة Rocket.Chat. أما الوضع المستقل فيبقي الخادم خاصًا تمامًا وخاليًا من أي اعتمادية خارجية، لكن الإشعارات الفورية على iOS وAndroid تتوقف عن العمل، لأن Apple وGoogle لا تسمحان لتطبيق مبني ذاتيًا بحيازة شهادات الدفع (push)؛ فالتطبيقات الرسمية تمرّ عبر بوابة السحابة. اختر الوضع المستقل إن كانت الخصوصية هي بيت القصيد وكان مستخدموك يعيشون داخل تطبيق الويب؛ واختر التسجيل إن كانت الإشعارات الفورية على الجوال غير قابلة للتنازل عنها. يمكنك تغيير رأيك لاحقًا من قسم Admin.

أحكم الإغلاق قبل أن تدعو أحدًا

يأتي Rocket.Chat مع التسجيل المفتوح مفعّلًا — فبشكل افتراضي يكون Registration Form مضبوطًا على Public، بحيث يستطيع أي شخص يعثر على الرابط إنشاء حساب. وعلى اسم مضيف عام هذا باب مفتوح على مصراعيه. اذهب إلى Admin → Settings → Accounts → Registration واضبط Registration Form على Disabled، لتنشئ الحسابات يدويًا أو عبر رابط دعوة، أو على Secret URL. وطالما أنت في هذه الصفحة، أطفئ Allow Anonymous Read وAllow Anonymous Write ما لم ترغب تحديدًا في قناة عامة للقراءة فقط.

قرّر أيضًا إلى أين تذهب الملفات المرفوعة. تخزين File Upload الافتراضي هو GridFS، الذي يخزّن كل صورة ومرفق داخل MongoDB نفسه. هذا بسيط، لكنه يعني أن قاعدة بياناتك — وكل mongodump تأخذه — تنمو بلا حدود مع لصق الناس لقطات الشاشة. من Admin → Settings → File Upload يمكنك تحويل التخزين إلى نظام الملفات المحلي أو دلو (bucket) متوافق مع S3، وضبط حجم أقصى معقول للملف. لفريق صغير يكفي GridFS؛ فقط اعلم أن نسخك الاحتياطية تزداد ثقلًا مع الوقت.

النسخ الاحتياطي بـ mongodump

كل بياناتك تقيم في وحدة التخزين (volume) mongodb_data. لا تكتفِ بنسخ وحدة التخزين من تحت قاعدة بيانات قيد التشغيل — خذ نسخة (dump) متّسقة بالأمر mongodump، مُوجَّهة إلى ملف على المضيف:

sudo docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > rocketchat-$(date +%F).archive.gz

هذا الأرشيف الواحد المضغوط بـ gzip هو مساحة عملك بأكملها: المستخدمون، والقنوات، والرسائل، والإعدادات، وإن أبقيت الملفات المرفوعة على GridFS، فالملفات أيضًا. وإن نقلت الملفات المرفوعة إلى نظام الملفات أو S3، فانسخ ذلك المخزن احتياطيًا بشكل منفصل. استعِد على حزمة جديدة بتهيئة مجموعة النسخ المتماثلة أولًا، ثم:

sudo docker compose exec -T mongodb mongorestore --archive --gzip --drop < rocketchat-2026-07-15.archive.gz

انسخ الأرشيف خارج الجهاز — تخزين كائنات (object storage)، أو خادم آخر، أي مكان لا يأخذ فيه موت الـ VPS النسخة الاحتياطية معه — وشغّل النسخ من cron كل ليلة. النسخة الاحتياطية التي لم تستعدها قط مجرد أمنية، لا نسخة احتياطية؛ جرّب الاستعادة مرة واحدة على VPS يمكن التخلص منه لتعرف أنها تعمل قبل أن تحتاج إليها.

الترقيات: ثبّت الوسوم، اقرأ الملاحظات، احترم مصفوفة Mongo

قاعدتان تُبقيان الترقيات مملة بالمعنى الجيد. أولًا، رقِّ Rocket.Chat إصدارًا رئيسيًا واحدًا في كل مرة. فهو يشغّل ترحيلات مخطط (schema) عند الإقلاع ويرفض عمدًا القفز بين الإصدارات الرئيسية؛ حاول الانتقال من 6.x مباشرة إلى 8.x وسيتوقف بخطأ ترحيل بدلًا من إفساد بياناتك. ارفع وسم الصورة إلى أحدث إصدار من الإصدار الرئيسي التالي، واقرأ ملاحظات ذلك الإصدار بحثًا عن تغييرات جذرية، ونفّذ docker compose up -d، وراقب السجلّات حتى تنتهي الترحيلات قبل أن تتابع. ثانيًا، التزم بمصفوفة دعم MongoDB. كل إصدار من Rocket.Chat يدعم مجموعة محددة من إصدارات MongoDB، ويخبرك الأمر curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions بأيها. وعندما تنقل MongoDB فعليًا — لنقل من 7.0 إلى 8.0 — تقدّم إصدارًا رئيسيًا واحدًا في كل خطوة واضبط إصدار توافق الميزات (feature-compatibility version) بعد كل قفزة. وعلى MongoDB 8.0 يتطلب هذا الأمر تمرير confirm: true صراحة، وإلا رفض مع رسالة تطلب منك إعادة تنفيذه مع علامة التأكيد:

sudo docker compose exec mongodb mongosh --eval 'db.adminCommand({setFeatureCompatibilityVersion: "8.0", confirm: true})'

خذ نسخة mongodump قبل كل ترقية لأي من المكوّنين. هذه هي بوليصة التأمين بأكملها.

أنماط الفشل، مع النصوص الدقيقة

يدخل Rocket.Chat في حلقة إعادة تشغيل فور تنفيذ docker compose up، ويمتلئ docker compose logs rocketchat بـ MongoServerSelectionError. MongoDB يعمل لكن برنامج التشغيل لا يستطيع اختيار عقدة أساسية، والنص الدقيق يخبرك بالخطأ الذي ارتكبته. Server selection timed out after 30000 ms مع نوع طوبولوجيا ReplicaSetNoPrimary يعني أنك لم تنفّذ rs.initiate() قط — المجموعة لا تملك إعدادات بعد. أما getaddrinfo ENOTFOUND متبوعًا بتجزئة عشوائية فيعني أنك هيّأت من دون host: "mongodb:27017" الصريح، فأعلن MongoDB عن اسم مضيف حاوية غير قابل للحل. شخّص المشكلة بالأمر sudo docker compose exec mongodb mongosh --eval 'rs.status()': فإن أظهر الخطأ MongoServerError: no replset config has been received، هيّئ المجموعة؛ وإن أظهر عضوًا اسمه name تجزئة عشوائية، أعد التهيئة باسم الخدمة.

تُحمَّل واجهة الويب لكن تسجيل الدخول يدور بلا توقف ولا يكتمل أبدًا. افتح وحدة تحكم المتصفح وسترى WebSocket connection to 'wss://chat.example.com/websocket' failed. هذا يكاد يكون دائمًا عدم تطابق في ROOT_URL أو وكيلًا لا يمرّر ترويسات الترقية. تأكد من أن ROOT_URL يساوي العنوان العام بالضبط بما في ذلك https://، وأن كتلة location في nginx تضبط Upgrade وConnection "upgrade" مع proxy_http_version 1.1. غيّر أيًّا منهما وأعد تنفيذ docker compose up -d.

حاوية تستمر في التوقف ويعرضها docker compose ps بحالة Restarting. ينقطع docker compose logs في منتصف سطر، ويُظهر sudo dmesg | tail رسالة Out of memory: Killed process 12345 (mongod) من قاتل نفاد الذاكرة (oom-killer)؛ ورمز الخروج هو 137. الجهاز نفد منه RAM. الحل الحقيقي هو VPS أكبر — 4 GB كحد أدنى. وكحل مؤقت أضف مساحة تبديل (swap) واحصر ذاكرة MongoDB المؤقتة بالخيار --wiredTigerCacheSizeGB 1 في command الخاص به، لكن الـ swap لا يفعل أكثر من تأجيل نفاد الذاكرة التالي تحت حمل حقيقي:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

يفشل docker compose up بالخطأ Error response from daemon: driver failed programming external connectivity ... bind: address already in use. شيء ما يحتلّ المنفذ 3000 بالفعل — غالبًا حاوية Rocket.Chat سابقة لم تتوقف بنظافة، أو تطبيق آخر. اعثر عليه بالأمر sudo ss -ltnp | grep :3000، وأوقف تلك العملية أو الحاوية، أو غيّر جانب المضيف من الربط إلى 127.0.0.1:3001:3000 وحدّث proxy_pass في وكيلك ليطابق ذلك.

FAQ

هل يحتاج Rocket.Chat حقًا إلى مجموعة نسخ متماثلة في MongoDB؟

نعم، حتى لخادم واحد بعقدة قاعدة بيانات واحدة. يسلّم Rocket.Chat الرسائل في الوقت الفعلي باستخدام تدفقات التغيير في MongoDB، وتدفقات التغيير ميزة مقصورة على مجموعات النسخ المتماثلة — فلا يستطيع mongod مستقل فتح واحد منها. لست بحاجة إلى أجهزة متعددة؛ فأنت تشغّل حاوية MongoDB واحدة بدأت بالخيار --replSet rs0 وتهيّئ مجموعة بعضو واحد بالأمر rs.initiate(). تجاوز هذه الخطوة يجعل برنامج التشغيل لا يجد عقدة أساسية أبدًا، فيدخل Rocket.Chat في حلقة إعادة تشغيل مع MongoServerSelectionError: Server selection timed out ولا ينهي الإقلاع أبدًا.

كم من RAM يحتاج Rocket.Chat المستضاف ذاتيًا؟

خطّط لـ 4 GB كحد أدنى عملي، و8 GB لفريق نشط. تستخدم عملية Node الخاصة بـ Rocket.Chat نحو 1 إلى 1.5 GB، ويستحوذ MongoDB على نحو نصف RAM المتبقية لذاكرته المؤقتة WiredTiger، لذا على جهاز بسعة 2 GB يتصادم الاثنان ويُنهي قاتل نفاد الذاكرة عملية mongod تحت أي حمل حقيقي، مُظهرًا Killed في السجلّات ورمز الخروج 137. 2 GB تكفي فقط لتقييم البرنامج مع مستخدم اختبار أو اثنين.

كيف أضع Rocket.Chat خلف HTTPS؟

شغّل وكيلًا عكسيًا على الـ VPS نفسه ينهي TLS ويوجّه الطلبات إلى 127.0.0.1:3000، واضبط ROOT_URL الخاص بالحاوية على عنوانك العام https://. يجب أن يمرّر الوكيل ترويسات ترقية WebSocket وإلا سيتجمد تسجيل الدخول. Certbot مع nginx هو الإعداد الأبسط لتطبيق واحد؛ وTraefik أنظف إن كنت تشغّل عدة حاويات خلف وكيل واحد وتريد إدارة تلقائية للشهادات.

كيف أنسخ احتياطيًا Rocket.Chat المستضاف ذاتيًا؟

خذ نسخة متّسقة من قاعدة البيانات بالأمر mongodump بدلًا من نسخ وحدة التخزين: docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > backup.archive.gz. يحتوي ذلك الأرشيف على المستخدمين والقنوات والرسائل والإعدادات، إضافة إلى الملفات المرفوعة إن أبقيت التخزين على GridFS. انسخه خارج الخادم، وأتمِتْه ليلًا بـ cron، وتدرّب على mongorestore على جهاز يمكن التخلص منه لتعرف أن الاستعادة تعمل فعلًا.

كيف أرقّي Rocket.Chat من دون إفساد MongoDB؟

رقِّ Rocket.Chat إصدارًا رئيسيًا واحدًا في كل مرة — فهو يشغّل ترحيلات عند الإقلاع ويرفض تخطي الإصدارات الرئيسية — واقرأ ملاحظات كل إصدار قبل رفع وسم الصورة المثبّت. تحقق من إصدارات MongoDB التي يدعمها إصدارك المستهدف بالأمر curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions، وعندما تنقل MongoDB، تقدّم إصدارًا رئيسيًا واحدًا في كل خطوة واضبط setFeatureCompatibilityVersion بالخيار confirm: true بعد كل قفزة. خذ دائمًا نسخة mongodump أولًا.