SSD Nodes Learn
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-07-24

نصب Rocket.Chat با Docker Compose

راهنمای کامل نصب Rocket.Chat روی VPS با استفاده از Docker Compose. تنظیمات MongoDB replica set، پروتکل TLS و مدیریت حافظه RAM برای جلوگیری از خطا.

آنچه در حال ساخت آن هستید

یک چت تیمی خصوصی با مالکیت کامل شما: Rocket.Chat که روی VPS شخصی خودتان و تحت Docker Compose اجرا می‌شود، با پروتکل TLS محافظت شده است، و تمام پیام‌ها در یک پایگاه داده MongoDB ذخیره می‌شوند که قابلیت پشتیبان‌گیری و انتقال دارند. Rocket.Chat یک جایگزین متن‌باز و بالغ برای Slack و Teams است که قابلیت‌هایی مانند کانال‌ها، پیام‌های مستقیم، رشته‌گفتگوها (threads)، اشتراک‌گذاری فایل، و تماس صوتی و تصویری را روی سخت‌افزاری که اجاره کرده و کنترل می‌کنید، فراهم می‌کند. این اپلیکیشن یک کانتینر واحد است که در عرض چند دقیقه اجرا می‌شود. تمام بخش‌هایی که ممکن است با خطا مواجه شوند، در پایگاه داده مجاور آن قرار دارند؛ بنابراین بخش اعظم این راهنما درباره MongoDB است. به‌طور مشخص، یک نکته وجود دارد که در اولین برخورد همه را غافلگیر می‌کند: Rocket.Chat روی یک MongoDB مستقل (standalone) اجرا نمی‌شود. این برنامه به یک replica set نیاز دارد، حتی اگر آن "set" تنها شامل یک node باشد.

پیش‌نیازها، و محاسبات RAM که کسی به شما نمی‌گوید

ابعاد سرور را واقع‌بینانه انتخاب کنید. حداقل مشخصات مورد نیاز برای یک تیم کوچک 2 vCPU و 4 GB RAM است. فرآیند Node.js در Rocket.Chat به تنهایی حدود 1 تا 1.5 GB فضا نیاز دارد و حافظه cache در MongoDB (WiredTiger) به صورت پیش‌فرض حدود نیمی از RAM باقی‌مانده را اشغال می‌کند. در یک VPS با 2 GB، هر دو در هنگام بوت شدن جا می‌شوند، اما به محض رسیدن ترافیک واقعی با هم برخورد می‌کنند: حافظه cache در MongoDB افزایش می‌یابد، Heap در Node افزایش می‌یابد، صفحات حافظه در Kernel تمام می‌شوند و OOM killer فرآیند بزرگ را متوقف می‌کند — که معمولاً mongod است. کانتینر خطای Killed را چاپ می‌کند، Docker آن را ری‌استارت می‌کند و شما سرور چتی خواهید داشت که در زیر بار ترافیکی که باید به راحتی تحمل کند، هر چند دقیقه یک‌بار از دسترس خارج می‌شود. ظرفیت 2 GB برای تست کردن با 2 کاربر مناسب است؛ اما برای یک سرور تیمی مناسب نیست. کار را با 4 GB شروع کنید و اگر ده‌ها کاربر همزمان، تماس‌های ویدئویی یا تاریخچه آپلود رو به رشد دارید، 8 GB اختصاص دهید.

همچنین قبل از شروع، باید سه مورد زیر آماده باشد. یک نام دامنه با یک A record که به IP عمومی VPS اشاره کند؛ قابلیت‌های real-time و کلاینت‌های موبایل Rocket.Chat به یک hostname پایدار نیاز دارند، نه یک IP ساده. پورت‌های 80 و 443 در هر دو فایروال سرور و فایروال شبکه ارائه‌دهنده باز باشند (در اکثر پنل‌ها، فایروال شبکه یک کنترل مجزا است). و یک VPS تازه با سیستم‌عامل Ubuntu 24.04 KVM با دسترسی root یا sudo. اگر هنوز در حال تصمیم‌گیری هستید که آیا یک سرور چت اولین سرویس مناسب برای میزبانی است یا خیر، راهنمای آنچه ارزش self-hosting در 2026 را دارد مزایا و معایب را بررسی می‌کند.

نصب Docker engine و افزونه Compose

از مخزن apt اختصاصی Docker استفاده کنید، نه از بسته docker.io که Ubuntu ارائه می‌دهد و نه از فایل باینری قدیمی و مستقل docker-compose در Python. نسخه مدرن Compose یک افزونه Docker است که با دستور docker compose اجرا می‌شود — با یک فاصله (space) و بدون خط تیره (hyphen). نسخه قدیمی docker-compose v1 از چرخه پشتیبانی خارج شده است و سینتکس مربوط به 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 به عنوان یک replica set تک‌گره

این بخش معمولاً اشتباه درک می‌شود، پس آن را با دقت بخوانید. Rocket.Chat از change streams در MongoDB استفاده می‌کند تا پیام‌های جدید را در لحظه به کلاینت‌های متصل ارسال کند؛ قابلیت change streams فقط در یک replica set در دسترس است. اگر Rocket.Chat را به یک mongod معمولی و standalone متصل کنید، اتصال برقرار می‌شود اما باز کردن change stream با خطا مواجه شده و سیستم در یک حلقه restart-loop بی‌پایان قرار می‌گیرد. راه حل پیچیده نیست: شما یک کانتینر معمولی MongoDB اجرا می‌کنید، اما آن را با --replSet استارت می‌زنید و سپس یک set تک‌عضو را مقداردهی اولیه (initialise) می‌کنید.

یک دایرکتوری کاری و یک 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 روی همان سیستم باید به آن دسترسی داشته باشد؛ متصل کردن آن به تمام اینترفیس‌ها باعث می‌شود صفحه ورود با متن ساده (plaintext) مستقیماً در اینترنت عمومی قرار بگیرد. MongoDB اصلاً روی host منتشر نشده است؛ این دیتابیس فقط از طریق شبکه داخلی Compose و با نام mongodb قابل دسترسی است که دقیقاً همان hostname مورد استفاده توسط MONGO_URL است. MONGO_URL شامل ?replicaSet=rs0 است؛ اگر آن را حذف کنید، driver سرور را به عنوان standalone در نظر می‌گیرد در حالی که یک replica set است و باز هم change streams با خطا مواجه می‌شوند. MONGO_OPLOG_URL به دیتابیس local که oplog در آن قرار دارد اشاره می‌کند؛ Rocket.Chat مدرن استفاده از change streams را ترجیح می‌دهد، اما تنظیم کردن آن بی‌خطر است و کدهای قدیمی‌تر را بدون مشکل اجرا می‌کند. depends_on از condition: service_healthy استفاده می‌کند، بنابراین Compose منتظر می‌ماند تا MongoDB به یک ping پاسخ دهد و سپس Rocket.Chat را استارت می‌کند؛ این وظیفه healthcheck است.

از تگ‌های نسخه واقعی برای هر دو ایمیج استفاده کنید — در اینجا mongo:8.0 و یک نسخه مشخص از Rocket.Chat مانند 8.5.1 — و هرگز از :latest استفاده نکنید، زیرا یک docker pull بدون نظارت را به یک ارتقای تصادفی و غیرقابل انتقال (un-migratable) تبدیل می‌کند. قبل از انتخاب نسخه، نسخه پایدار فعلی Rocket.Chat و نسخه‌های مورد حمایت MongoDB را بررسی کنید. Rocket.Chat برای هر نسخه یک سند اطلاعاتی ماشین‌خوان منتشر می‌کند: curl -s https://releases.rocket.chat/8.5.1/info | jq '{compatibleMongoVersions, lts}' برای نسخه 8.5.1 مقدار compatibleMongoVersions: ["8.0"] را برمی‌گرداند، بنابراین mongo:8.0 تنها موتور مورد حمایت است، به همراه یک فلگ lts که به شما می‌گوید آیا آن نسخه یک نسخه با پشتیبانی طولانی‌مدت (LTS) است یا خیر، تا بتوانید برای سروری که نمی‌خواهید مدام نیاز به مدیریت دستی داشته باشد، آن را ثابت (pin) کنید.

Initialise the replica set

اجرای stack:

sudo docker compose up -d

Rocket.Chat بلافاصله کرش می‌کند و Docker مدام آن را restart می‌کند؛ این رفتار طبیعی است، زیرا replica set هنوز وجود ندارد. یک بار آن را به صورت دستی ایجاد کنید:

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

نتیجه صحیح { ok: 1 } است. ظرف چند ثانیه، تک‌node خود را به عنوان primary انتخاب می‌کند؛ با دستور زیر آن را تایید کنید:

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

خروجی باید PRIMARY باشد. مهم‌ترین جزئیات در تمام این صفحه، آرگومان host: "mongodb:27017" است. اگر دستور rs.initiate() را بدون لیست اعضا اجرا کنید، MongoDB نام replica set را با استفاده از hostname داخلی کانتینر اعلام می‌کند که یک هش تصادفی مانند a1b2c3d4e5f6 است. Rocket.Chat که از داخل کانتینر خود متصل می‌شود، نمی‌تواند آن نام را resolve کند؛ بنابراین MongoDB driver در مرحله DNS با خطا مواجه شده و در یک حلقه بی‌نهایت با لاگ MongoServerSelectionError: getaddrinfo ENOTFOUND a1b2c3d4e5f6 قرار می‌گیرد. همیشه فرآیند را با نام سرویس صریح که با MONGO_URL مطابقت دارد، شروع کنید.

اولین اجرا: فرآیند بالا آمدن را مشاهده کنید

پس از اینکه set به حالت primary تغییر یافت، اولین ری‌استارت Rocket.Chat بدون مشکل انجام می‌شود و فرآیند مهاجرت (migration) اولیه را آغاز می‌کند. لاگ‌ها را دنبال کنید:

sudo docker compose logs -f rocketchat

خطی که منتظر آن هستید، بنر شروع به کار است:

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

اولین اجرا کند انجام می‌شود؛ اپلیکیشن در حال اجرای database migrations و ساخت indexها است، بنابراین قبل از نگرانی، یک یا دو دقیقه صبر کنید. اگر لاگ به جای مورد انتظار، عبارت MongoServerSelectionError: Server selection timed out after 30000 ms را همراه با topology با نوع ReplicaSetNoPrimary تکرار کرد، یعنی replica set مقداردهی اولیه نشده است؛ اگر عبارت getaddrinfo ENOTFOUND را روی یک hash تصادفی تکرار کرد، یعنی با host اشتباه مقداردهی شده است. در هر دو حالت، یک مرحله به عقب برگردید. به محض مشاهده SERVER RUNNING، Rocket.Chat در پورت 127.0.0.1:3000 در حال گوش دادن است و زمان آن رسیده است که یک hostname واقعی و TLS را برای آن تنظیم کنید.

استفاده از TLS

هرگز Rocket.Chat را از طریق HTTP معمولی در معرض شبکه قرار ندهید. با ورود به سیستم از طریق http://، رمز عبور مدیریت خود را به هر کسی که در مسیر قرار دارد، تحویل می‌دهید. TLS را در یک reverse proxy روی همان سرور Terminate کنید و سپس درخواست‌ها را به 127.0.0.1:3000 ارسال کنید. دو نکته اهمیت دارد: پروکسی باید headers مربوط به WebSocket upgrade را ارسال کند، زیرا Rocket.Chat یک اپلیکیشن real-time است و بدون آن‌ها از کار می‌افتد؛ و همچنین ROOT_URL کانتینر باید دقیقاً با آدرس HTTPS عمومی که کاربران تایپ می‌کنند، مطابقت داشته باشد.

با یک nginx server block ساده شروع کنید که به اپلیکیشن proxy می‌کند و upgrade headers را ارسال می‌کند. آن را در مسیر /etc/nginx/sites-available/rocketchat ذخیره کنید، با یک symlink آن را در sites-enabled قرار دهید و سپس reload کنید:

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; و بدون certificate حتی از sudo nginx -t هم عبور نخواهد کرد. nginx را reload کنید (sudo nginx -t && sudo systemctl reload nginx)، سپس certificate را صادر کنید. ساده‌ترین مسیر در Ubuntu این است: Let's Encrypt TLS certificates with Certbot and nginx: certbot --nginx بلوک بالا را جایگزین می‌کند، listen 443 ssl;، خطوط ssl_certificate و یک redirect خودکار از 80 به 443 را اضافه می‌کند و زمان تمدید را نیز برای شما برنامه‌ریزی می‌کند. اگر از قبل چندین کانتینر را پشت یک پروکسی اجرا می‌کنید، Traefik with automatic TLS for many Docker apps گزینه مرتب‌تری است — برچسب‌های router و service را به سرویس rocketchat اضافه کنید تا Traefik درخواست‌ها را دریافت و certificate را برای شما تمدید کند، بدون اینکه نیازی به nginx block باشد. در هر دو حالت، مقدار ROOT_URL را در compose.yml برابر با https://chat.example.com قرار دهید و sudo docker compose up -d را مجدداً اجرا کنید تا کانتینر تغییرات را دریافت کند. اگر می‌خواهید سرور به جای اینترنت عمومی، فقط از داخل شبکه خودتان قابل دسترسی باشد، از یک self-hosted WireGuard VPN on the VPS استفاده کنید و پروکسی را به آدرس tunnel متصل کنید.

Wizard تنظیمات اولین اجرا

به مسیر https://chat.example.com و Rocket.Chat بروید. Rocket.Chat شما را از طریق یک wizard کوتاه راهنمایی می‌کند. ابتدا، حساب admin — شامل نام واقعی، username، email و یک password قوی؛ این تنها حسابی است که وجود دارد، پس آن را گم نکنید. سپس، اطلاعات سازمان و سرور — شامل name، industry، size، site name و default language؛ این موارد جنبه ظاهری دارند، آن‌ها را تکمیل کنید و ادامه دهید. سپس انتخاب مهم: ثبت این workspace در Rocket.Chat Cloud، یا استفاده از حالت standalone.

ثبت کردن (Registering) باعث فعال شدن mobile push notifications از طریق gateway شرکت Rocket.Chat و add-on marketplace می‌شود، اما در مقابل، یک رابطه control-plane با cloud شرکت Rocket.Chat برقرار می‌گردد. حالت standalone سرور را کاملاً private و بدون وابستگی نگه می‌دارد، اما push notifications در iOS و Android از کار می‌افتد؛ زیرا Apple و Google اجازه نمی‌دهند یک اپلیکیشن self-built، گواهی‌های push را نگه دارد — اپلیکیشن‌های رسمی از طریق cloud gateway مسیریابی می‌شوند. اگر هدف اصلی شما privacy است و کاربران شما از web app استفاده می‌کنند، حالت standalone را انتخاب کنید؛ اگر mobile push برای شما الزامی است، ثبت در cloud را انتخاب کنید. شما می‌توانید بعداً در بخش Admin تنظیمات خود را تغییر دهید.

پیش از دعوت کردن دیگران، امنیت را برقرار کنید

Rocket.Chat به صورت پیش‌فرض با حالت open registration on عرضه می‌شود؛ یعنی Registration Form روی Public تنظیم شده است و هر کسی که URL را پیدا کند، می‌تواند حساب کاربری بسازد. این وضعیت در یک hostname عمومی مانند یک در باز عمل می‌کند. به مسیر Admin → Settings → Accounts → Registration بروید و Registration Form را روی Disabled تنظیم کنید تا حساب‌ها را به صورت دستی یا با لینک دعوت بسازید، و یا آن را روی Secret URL قرار دهید. در همین بخش، اگر قصد ندارید کانال عمومیِ فقط-خواندنی (read-only) داشته باشید، گزینه‌های Allow Anonymous Read و Allow Anonymous Write را غیرفعال کنید.

محل ذخیره‌سازی فایل‌های آپلود شده را نیز تعیین کنید. حالت پیش‌فرض برای File Upload، استفاده از GridFS است که هر تصویر و پیوست را درون خودِ MongoDB ذخیره می‌کند. این روش ساده است، اما به این معناست که با ارسال اسکرین‌شات توسط کاربران، حجم دیتابیس شما — و هر mongodump که ثبت می‌کنید — بدون محدودیت افزایش می‌یابد. در مسیر Admin → Settings → File Upload می‌توانید نوع ذخیره‌سازی را به local filesystem یا یک S3-compatible bucket تغییر دهید و یک حداکثر حجم منطقی برای فایل‌ها تعیین کنید. برای تیم‌های کوچک، استفاده از GridFS مناسب است؛ فقط توجه داشته باشید که حجم بک‌آپ‌های شما با گذشت زمان بیشتر می‌شود.

Backups with mongodump

تمام داده‌های شما در volume با نام mongodb_data قرار دارند. هرگز volume را در حالی که database در حال اجرا است، کپی نکنید؛ بلکه از mongodump برای تهیه یک dump منسجم استفاده کنید و خروجی را به یک فایل در host هدایت کنید:

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

این آرشیو واحد که با gzipped فشرده شده است، شامل تمام فضای کاری شماست: کاربران، کانال‌ها، پیام‌ها، تنظیمات و اگر فایل‌های آپلود شده را در GridFS قرار داده باشید، شامل فایل‌ها نیز می‌شود. اگر فایل‌های آپلود شده را به filesystem یا S3 منتقل کرده‌اید، از آن ذخیره‌ساز به صورت جداگانه پشتیبان تهیه کنید. برای بازیابی (Restore) روی یک stack جدید، ابتدا replica set را مقداردهی اولیه کنید و سپس دستور زیر را اجرا کنید:

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

آرشیو را خارج از سرور کپی کنید — از object storage، یک سرور دیگر یا هر جایی که با از کار افتادن VPS، بک‌آپ نیز از بین نرود استفاده کنید — و دستور dump را هر شب از طریق cron اجرا کنید. بک‌آپی که تا به حال بازیابی نشده است، تنها یک امید است، نه یک بک‌آپ؛ یک بار فرآیند restore را روی یک VPS موقت امتحان کنید تا قبل از نیاز واقعی، از کارکرد صحیح آن مطمئن شوید.

Upgrades: pin tags, read the notes, respect the Mongo matrix

دو قانون باعث می‌شوند فرآیند ارتقا بدون مشکل انجام شود. اول، Rocket.Chat را در هر مرحله فقط یک نسخه Major ارتقا دهید. این برنامه هنگام اجرا، عملیات schema migration را انجام می‌دهد و از پرش مستقیم بین نسخه‌های Major خودداری می‌کند؛ اگر سعی کنید مستقیماً از 6.x به 8.x بروید، به جای خراب شدن داده‌ها، با خطای migration متوقف می‌شود. تگ image را به آخرین نسخه از نسخه Major بعدی تغییر دهید، یادداشت‌های آن نسخه را برای بررسی تغییرات ساختاری (breaking changes) بخوانید، دستور docker compose up -d را اجرا کنید و منتظر بمانید تا فرآیند migration در logs تکمیل شود و سپس ادامه دهید. دوم، به ماتریس پشتیبانی MongoDB احترام بگذارید. هر نسخه از Rocket.Chat از مجموعه مشخصی از نسخه‌های MongoDB پشتیبانی می‌کند و curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions مشخص می‌کند کدام نسخه مورد تایید است. هنگام ارتقای MongoDB — مثلاً از 7.0 به 8.0 — هر مرحله را یک نسخه Major انجام دهید و پس از هر گام، feature-compatibility version را تنظیم کنید. در MongoDB 8.0، این دستور نیاز به یک confirm: true صریح دارد، در غیر این صورت با پیامی مبنی بر نیاز به اجرای مجدد با پرچم تایید (confirmation flag) متوقف می‌شود:

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

قبل از هر ارتقا برای هر یک از این دو بخش، یک mongodump تهیه کنید. این تنها راه تضمین امنیت داده‌ها است.

حالت‌های خطا و رشته‌های دقیق

Rocket.Chat بلافاصله پس از docker compose up در حلقه restart-loop می‌افتد و docker compose logs rocketchat با یک MongoServerSelectionError پر می‌شود. MongoDB در حال اجرا است اما driver نمی‌تواند یک primary انتخاب کند؛ رشته دقیق خطا نشان می‌دهد که چه اشتباهی انجام داده‌اید. Server selection timed out after 30000 ms با topology type از نوع ReplicaSetNoPrimary به این معناست که شما هرگز rs.initiate() را اجرا نکرده‌اید — set هنوز پیکربندی ندارد. getaddrinfo ENOTFOUND که با یک hash تصادفی همراه است، به این معناست که شما بدون استفاده از host: "mongodb:27017" صریح، عملیات initiate را شروع کرده‌اید؛ بنابراین MongoDB یک hostname غیرقابل حل برای container تبلیغ کرده است. با استفاده از sudo docker compose exec mongodb mongosh --eval 'rs.status()' عیب‌یابی کنید: اگر خطای MongoServerError: no replset config has been received دریافت کردید، set را initiate کنید؛ اگر عضوی را مشاهده کردید که name آن یک hash تصادفی است، عملیات re-initiate را با استفاده از service name انجام دهید.

رابط کاربری وب (web UI) بارگذاری می‌شود اما فرآیند ورود (login) در حالت انتظار (spin) باقی می‌ماند و هرگز تکمیل نمی‌شود. کنسول مرورگر را باز کنید تا با WebSocket connection to 'wss://chat.example.com/websocket' failed مواجه شوید. این حالت تقریباً همیشه ناشی از عدم تطابق ROOT_URL یا وجود یک proxy است که headers مربوط به upgrade را ارسال نمی‌کند. بررسی کنید که ROOT_URL دقیقاً برابر با آدرس عمومی شامل https:// باشد و بلوک nginx location شما، مقادیر Upgrade و Connection "upgrade" را با proxy_http_version 1.1 تنظیم کرده باشد. پس از تغییر هر یک از این موارد، docker compose up -d را مجدداً اجرا کنید.

یک container مدام متوقف می‌شود و docker compose ps نشان می‌دهد که آن Restarting شده است. عبارت docker compose logs در میان خط قطع می‌شود و sudo dmesg | tail نشان‌دهنده Out of memory: Killed process 12345 (mongod) از سمت oom-killer است؛ کد خروج (exit code) 137 است. حافظه RAM سیستم تمام شده است. راه حل اصلی استفاده از یک VPS بزرگتر است — حداقل 4 GB. به عنوان یک راه حل موقت، swap اضافه کنید و کش MongoDB را با استفاده از --wiredTigerCacheSizeGB 1 در command محدود کنید، اما توجه داشته باشید که swap فقط باعث تأخیر در وقوع OOM بعدی تحت بار واقعی می‌شود:

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 استفاده می‌کند — اغلب یک container قبلی Rocket.Chat که به درستی متوقف نشده است، یا برنامه‌ای دیگر. آن را با استفاده از sudo ss -ltnp | grep :3000 پیدا کنید، آن process یا container را متوقف کنید، یا سمت host در mapping را به 127.0.0.1:3001:3000 تغییر دهید و proxy_pass پروکسی خود را مطابق با آن به‌روزرسانی کنید.

FAQ

آیا Rocket.Chat واقعاً به یک MongoDB replica set نیاز دارد؟

بله، حتی برای یک سرور واحد با یک node دیتابیس. Rocket.Chat پیام‌ها را در حالت real time و با استفاده از MongoDB change streams ارسال می‌کند؛ قابلیت change streams فقط در replica-setها در دسترس است و یک standalone mongod نمی‌تواند آن را باز کند. نیازی به چندین ماشین ندارید؛ کافی است یک container مربوط به MongoDB را با دستور --replSet rs0 اجرا کرده و یک set تک‌عضو را با rs.initiate() مقداردهی اولیه کنید. اگر این مرحله را انجام ندهید، driver هرگز یک primary پیدا نمی‌کند؛ در این صورت Rocket.Chat با خطای MongoServerSelectionError: Server selection timed out در یک حلقه restart قرار می‌گیرد و فرآیند بوت شدن آن هرگز تمام نمی‌شود.

Rocket.Chat که به صورت self-hosted نصب شده، به چه میزان RAM نیاز دارد؟

برای حداقل کاربردی، 4 GB و برای یک تیم پرکار، 8 GB در نظر بگیرید. فرآیند Node در Rocket.Chat حدود 1 تا 1.5 GB از حافظه را اشغال می‌کند و MongoDB تقریباً نیمی از RAM باقی‌مانده را برای WiredTiger cache اختصاص می‌دهد. بنابراین در یک سرور با 2 GB، این دو با هم تداخل پیدا می‌کنند و out-of-memory killer در هر بار بار کاری واقعی، mongod را متوقف می‌کند که منجر به خطای Killed در logs و exit code 137 می‌شود. مقدار 2 GB فقط برای ارزیابی نرم‌افزار با چند کاربر تست کافی است.

چگونه Rocket.Chat را پشت HTTPS قرار دهم؟

یک reverse proxy روی همان VPS اجرا کنید که TLS را پایان (terminate) داده و درخواست‌ها را به 127.0.0.1:3000 ارسال می‌کند؛ سپس ROOT_URL کانتینر را روی آدرس عمومی https:// خود تنظیم کنید. پروکسی باید WebSocket upgrade headers را ارسال کند، در غیر این صورت فرآیند login متوقف (hang) می‌شود. استفاده از Certbot به همراه nginx ساده‌ترین روش برای یک اپلیکیشن است؛ اگر چندین کانتینر را پشت یک پروکسی اجرا می‌کنید و مدیریت خودکار گواهینامه‌ها را می‌خواهید، Traefik تمیزتر عمل می‌کند.

چگونه از Rocket.Chat که به صورت self-hosted نصب شده، بک‌آپ بگیرم؟

به جای کپی کردن volume، از دستور mongodump برای گرفتن یک دیتابیس dump یکپارچه استفاده کنید: docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > backup.archive.gz. آن آرشیو شامل کاربران، کانال‌ها، پیام‌ها و تنظیمات، و همچنین فایل‌های آپلود شده (در صورت استفاده از GridFS) است. فایل را از سرور خارج کنید، آن را با cron به صورت شبانه خودکار کنید و یک mongorestore را روی یک سرور تست انجام دهید تا از کارکرد صحیح فرآیند بازیابی (restore) مطمئن شوید.

چگونه Rocket.Chat را بدون آسیب زدن به MongoDB ارتقا دهم؟

Rocket.Chat را در هر مرحله فقط یک نسخه major ارتقا دهید؛ این برنامه در هنگام بوت، migrations را اجرا می‌کند و اجازه پرش از نسخه‌های major را نمی‌دهد. قبل از تغییر image tag، یادداشت‌های هر نسخه را بخوانید. با استفاده از curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions بررسی کنید که نسخه هدف از کدام ورژن‌های MongoDB پشتیبانی می‌کند. هنگام ارتقای MongoDB، هر بار فقط یک نسخه major را تغییر دهید و بعد از هر مرحله، با استفاده از confirm: true، مقدار setFeatureCompatibilityVersion را تنظیم کنید. همیشه ابتدا یک mongodump بگیرید.