Hướng dẫn cài đặt Rocket.Chat bằng Docker Compose
Triển khai Rocket.Chat trên VPS với Docker Compose. Hướng dẫn chi tiết cách cấu hình MongoDB replica set bắt buộc, thiết lập TLS, quản lý backup và xử lý các lỗi thường gặp.
Bạn đang xây dựng cái gì
Một hệ thống chat nội bộ mà bạn hoàn toàn làm chủ: Rocket.Chat chạy trên VPS của riêng bạn bằng Docker Compose, được bảo mật bằng TLS, với mọi tin nhắn lưu trong database MongoDB mà bạn có thể backup và di chuyển. Rocket.Chat là giải pháp thay thế mã nguồn mở hoàn thiện cho Slack và Teams, hỗ trợ kênh, tin nhắn trực tiếp, luồng thảo luận, chia sẻ file, cùng tính năng thoại và video, tất cả trên phần cứng bạn thuê và kiểm soát. Tuy nhiên, đây không phải là lựa chọn duy nhất, và nếu bạn vẫn đang cân nhắc, So sánh Mattermost, Rocket.Chat, Synapse và Zulip sẽ liệt kê các yếu tố gây khó khăn về sau: RAM, database, mobile push, SSO và nâng cấp. Ứng dụng này là một container đơn lẻ có thể khởi chạy trong vài phút. Mọi vấn đề phát sinh thực tế đều nằm ở database đi kèm, vì vậy phần lớn hướng dẫn này tập trung vào MongoDB, đặc biệt là yêu cầu khiến mọi người bất ngờ lần đầu tiên: Rocket.Chat sẽ không chạy với một MongoDB đơn lẻ (standalone). Nó yêu cầu một replica set, ngay cả khi "set" đó chỉ có một node duy nhất.
Điều kiện tiên quyết và phép tính RAM mà không ai nói với bạn
Hãy sizing server một cách thực tế. Mức tối thiểu phù hợp cho một team nhỏ là 2 vCPU và 4 GB RAM. Process Node.js của Rocket.Chat thường cần khoảng 1 đến 1.5 GB riêng, còn cache WiredTiger của MongoDB mặc định lấy giá trị lớn hơn giữa 50% của (tổng RAM trừ 1 GB) và 0.256 GB. Mặc định này giả định mongod sử dụng riêng toàn bộ máy: giá trị được tính từ tổng RAM và không tính đến phần Node đang dùng, nên trên máy 4 GB nó sẽ là 1.5 GB, còn trên máy 2 GB là khoảng 0.5 GB, chưa tính heap của Node, phần bộ nhớ riêng của mongod bên ngoài cache và hệ điều hành. Trên VPS 2 GB, hai thành phần này có thể cùng chạy khi boot nhưng sẽ xung đột ngay khi có network traffic thực tế: MongoDB tăng cache, Node tăng heap, kernel hết page trống, rồi out-of-memory killer sẽ kill process lớn hơn, thường là mongod. Container in ra Killed, Docker restart container, và bạn có một chat server bị ngắt vài phút một lần dưới mức tải mà lẽ ra nó phải xử lý dễ dàng. 2 GB phù hợp để thử với hai người; không phù hợp làm server cho team. Hãy bắt đầu với 4 GB, và dùng 8 GB nếu bạn dự kiến có hàng chục user đồng thời, video call hoặc lịch sử upload tăng dần. Cũng cần dự trù cho mọi workload khác mà server phải chạy: đặt một workspace AFFiNE kiểu Notion trên cùng VPS sẽ thêm 4 container cùng tranh chấp các page RAM, nên phải cộng RAM cho chúng thêm vào nhu cầu của Rocket.Chat, không được lấy từ phần RAM đã cấp cho Rocket.Chat.
Bạn cũng cần chuẩn bị 3 thứ trước khi bắt đầu. Một domain name có A record trỏ đến public IP của VPS; các tính năng real-time và mobile client của Rocket.Chat cần hostname ổn định, không phải bare IP. Mở port 80 và 443 trên cả firewall của server lẫn network firewall của provider; trên hầu hết panel, đây là một control riêng. Và một KVM VPS Ubuntu 24.04 mới cài, có quyền root hoặc sudo. Nếu bạn vẫn đang cân nhắc chat server có phải service đầu tiên nên self-host hay không, guide về những gì đáng self-host trong 2026 sẽ giúp bạn đánh giá các trade-off.
Cài Docker engine và Compose plugin
Sử dụng apt repository của Docker, không dùng package docker.io mà Ubuntu cung cấp và cũng không dùng binary Python docker-compose standalone đã lỗi thời. Compose hiện đại là một Docker plugin, được gọi bằng docker compose với một dấu cách, không phải dấu gạch nối. docker-compose v1 cũ đã hết vòng đời và xử lý không đúng cú pháp healthcheck cùng dependency bên dưới.
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-pluginXác nhận cả hai thành phần đã có:
sudo docker version
sudo docker compose versiondocker compose version in ra một dòng version là kiểm tra cần quan tâm. Các bản release hiện tại in ra Docker Compose version v5.x (v5.6.0, phát hành ngày 2 October 2026, là bản mới nhất tính đến 2026-10-10); bản cài đặt cũ có thể vẫn in ra v2.x, và Docker hỗ trợ cả hai. Docker mô tả Compose v5 là có chức năng giống hệt v2, nhưng đánh số là v5 để tránh nhầm với các định dạng file compose v2 và v3 cũ, vì vậy dùng bản nào cũng được trong hướng dẫn này. Nếu lệnh báo lỗi docker: 'compose' is not a docker command, plugin chưa được cài đặt. Bạn sẽ gặp các lỗi khó hiểu về sau, nên hãy sửa ngay tại đây.
Tệp compose: MongoDB dưới dạng replica set một node
Đây là phần thường bị cấu hình sai, vì vậy hãy đọc chậm. Rocket.Chat sử dụng change streams của MongoDB để đẩy tin nhắn mới đến các client đang kết nối theo thời gian thực. Change streams chỉ khả dụng trên replica set. Nếu trỏ Rocket.Chat vào một mongod standalone thông thường, ứng dụng sẽ kết nối, không mở được change stream rồi rơi vào vòng lặp restart vô hạn. Cách sửa không phức tạp: chạy một container MongoDB thông thường, khởi động container với --replSet rồi khởi tạo một set có một member.
Tạo một thư mục làm việc và một 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:Một số lựa chọn ở đây là có chủ đích. Port của Rocket.Chat được publish vào 127.0.0.1:3000, không phải 0.0.0.0. Bản thân app không có TLS, vì vậy chỉ reverse proxy trên cùng máy mới được truy cập app; bind app vào mọi interface sẽ đưa thẳng trang đăng nhập không mã hóa ra Internet công cộng. MongoDB không được publish ra host; nó chỉ có thể được truy cập qua network nội bộ của Compose bằng tên mongodb, đúng hostname mà MONGO_URL sử dụng. MONGO_URL truyền ?replicaSet=rs0, trong đó khai báo rõ tên set; MongoDB khuyến nghị thiết lập giá trị này để hành vi nhất quán giữa các driver. Bỏ tùy chọn này không tự làm hệ thống lỗi: directConnection mặc định là false, vì vậy driver vẫn phát hiện replica set và gửi operation đến primary, với điều kiện set được khởi tạo bằng hostname mà Rocket.Chat có thể phân giải. Phần tiếp theo sẽ xử lý việc đó. MONGO_OPLOG_URL trỏ đến database local, nơi lưu oplog; Rocket.Chat hiện đại ưu tiên change streams, nhưng thiết lập giá trị này không gây hại và giúp các code path cũ tiếp tục hoạt động. depends_on sử dụng condition: service_healthy, vì vậy Compose chờ MongoDB trả lời một ping rồi mới khởi động Rocket.Chat. Đó là mục đích của healthcheck.
Hãy pin tag phiên bản thực trên cả hai image, mongo:8.0 và một release Rocket.Chat cụ thể như 8.5.1 ở đây. Không bao giờ dùng :latest, vì nó biến một docker pull không có người giám sát thành một lần nâng cấp ngoài ý muốn và không thể migrate. Hãy kiểm tra release Rocket.Chat stable hiện tại cùng các phiên bản MongoDB được hỗ trợ trước khi pin. Rocket.Chat công bố một tài liệu info dạng machine-readable cho mỗi release: curl -s https://releases.rocket.chat/8.5.1/info | jq '{compatibleMongoVersions, lts}' trả về compatibleMongoVersions: ["8.0"] cho 8.5.1, vì vậy mongo:8.0 là engine duy nhất được hỗ trợ. Tài liệu này cũng có flag lts cho biết release đó có phải bản long-term-support đáng pin hay không, phù hợp với server mà bạn không muốn phải theo dõi thường xuyên. Không phải project nào cũng publish image theo phiên bản. Khi đó, hãy pin từ source: tự host trình theo dõi bài tập openGym nghĩa là checkout một git tag cụ thể và build từ tag đó, thay vì theo một branch luôn thay đổi.
Khởi tạo replica set
Khởi chạy stack:
sudo docker compose up -dRocket.Chat sẽ crash ngay lập tức và Docker sẽ liên tục khởi động lại nó, đây là điều bình thường vì replica set chưa tồn tại. Hãy tạo nó một lần bằng tay:
sudo docker compose exec mongodb mongosh --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "mongodb:27017"}]})'Kết quả đúng là { ok: 1 }. Trong vài giây, node đơn lẻ sẽ tự bầu chọn làm primary; xác nhận bằng lệnh:
sudo docker compose exec mongodb mongosh --quiet --eval 'rs.status().members[0].stateStr'Bạn cần thấy PRIMARY. Chi tiết quan trọng nhất trên toàn bộ trang này là tham số host: "mongodb:27017". Nếu bạn chạy lệnh rs.initiate() trần mà không có danh sách thành viên, MongoDB sẽ quảng bá replica set dưới hostname nội bộ của container, một chuỗi hash ngẫu nhiên như a1b2c3d4e5f6. Rocket.Chat, khi kết nối từ container của chính nó, không thể phân giải tên đó, nên driver MongoDB bị lỗi DNS và lặp vô tận với log MongoServerSelectionError: getaddrinfo ENOTFOUND a1b2c3d4e5f6. Luôn khởi tạo với tên service tường minh khớp với MONGO_URL của bạn.
Khởi động lần đầu: theo dõi quá trình khởi chạy
Khi set đã trở thành primary, lần khởi động lại tiếp theo của Rocket.Chat sẽ kết nối ổn định và bắt đầu các migration lần đầu. Hãy theo dõi log:
sudo docker compose logs -f rocketchatDòng bạn cần đợi là banner khởi động:
+--------------------------------------------+
SERVER RUNNING
Rocket.Chat Version: 8.5.1
NodeJS Version: 22.22.3 - x64
+--------------------------------------------+Lần khởi động đầu tiên thường chậm vì ứng dụng phải chạy migration database và xây dựng index, vì vậy hãy đợi một hoặc hai phút trước khi lo lắng. Nếu log lặp lại MongoServerSelectionError: Server selection timed out after 30000 ms với mô tả topology là loại ReplicaSetNoPrimary, nghĩa là replica set chưa được khởi tạo; nếu log lặp lại getaddrinfo ENOTFOUND với một hash ngẫu nhiên, nghĩa là nó đã được khởi tạo với sai hostname. Trong cả hai trường hợp, hãy quay lại bước trước. Khi bạn thấy SERVER RUNNING, Rocket.Chat đã lắng nghe trên 127.0.0.1:3000 và đây là lúc để đặt một hostname thực và TLS phía trước nó.
Đặt phía sau TLS
Đừng bao giờ để Rocket.Chat chạy trên HTTP thuần. Chỉ cần đăng nhập qua http:// một lần là bạn đã trao mật khẩu admin cho bất kỳ ai trên đường truyền. Hãy thực hiện TLS termination tại một reverse proxy trên cùng máy chủ và chuyển tiếp đến 127.0.0.1:3000. Có hai điều quan trọng: proxy phải chuyển tiếp các header WebSocket upgrade, vì Rocket.Chat hoạt động theo thời gian thực và sẽ lỗi nếu thiếu chúng, và ROOT_URL của container phải khớp chính xác với địa chỉ HTTPS công khai mà người dùng nhập vào.
Bắt đầu với một block server nginx HTTP thuần để proxy đến ứng dụng và chuyển tiếp các header upgrade. Lưu nó thành /etc/nginx/sites-available/rocketchat, tạo symlink vào sites-enabled, và 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;
}
}Hãy cứ để nó ở cổng 80 lúc này, một block với listen 443 ssl; mà không có chứng chỉ sẽ không vượt qua được sudo nginx -t. Reload nginx (sudo nginx -t && sudo systemctl reload nginx), sau đó cấp chứng chỉ. Cách gọn nhất trên Ubuntu là cấp chứng chỉ TLS Let's Encrypt với Certbot và nginx: certbot --nginx sẽ ghi đè block trên, thêm listen 443 ssl;, các dòng ssl_certificate, và tự động redirect từ 80 sang 443, đồng thời lên lịch gia hạn cho bạn. Nếu bạn đã chạy nhiều container sau một proxy, Traefik với TLS tự động cho nhiều ứng dụng Docker là tùy chọn gọn gàng hơn, hãy thêm các nhãn router và service vào service rocketchat và Traefik sẽ tự yêu cầu cũng như gia hạn chứng chỉ cho bạn, mà không cần bất kỳ block nginx nào. Dù chọn cách nào, hãy đặt ROOT_URL thành https://chat.example.com trong compose.yml và chạy lại sudo docker compose up -d để container nhận thay đổi. Nếu bạn muốn server chỉ có thể truy cập từ bên trong mạng nội bộ thay vì Internet công cộng, hãy đặt nó phía sau một VPN WireGuard tự host trên VPS và bind proxy vào địa chỉ tunnel.
Trình hướng dẫn thiết lập lần đầu
Truy cập https://chat.example.com. Rocket.Chat sẽ hướng dẫn bạn qua một trình wizard ngắn. Trước tiên là tài khoản admin, gồm tên thật, username, email và mật khẩu mạnh. Đây là tài khoản duy nhất tồn tại, vì vậy không được làm mất tài khoản này. Tiếp theo là thông tin tổ chức và server, gồm tên, ngành, quy mô, tên site và ngôn ngữ mặc định. Phần này chỉ mang tính hiển thị, hãy điền thông tin rồi tiếp tục. Sau đó là lựa chọn thực sự quan trọng: đăng ký workspace này với Rocket.Chat Cloud hoặc giữ ở chế độ standalone.
Đăng ký sẽ bật thông báo push trên mobile thông qua gateway của Rocket.Chat và marketplace add-on, nhưng đổi lại server có quan hệ với control plane trên cloud của Rocket.Chat. Các thông báo push gửi qua gateway cũng được tính vào giới hạn hàng tháng của workspace. Chế độ standalone giữ server hoàn toàn riêng tư và không phụ thuộc bên ngoài, nhưng các app iOS và Android chính thức sẽ không nhận được thông báo push. Theo tài liệu của Rocket.Chat, các app này chỉ hoạt động với cloud gateway của họ, và gateway sẽ không chạy trên workspace chưa đăng ký. Cách khắc phục là tự build một phiên bản mobile app gắn thương hiệu riêng: tắt gateway trong phần Push settings, nhập certificate APNs và credential Firebase Cloud Messaging của bạn, rồi yêu cầu người dùng cài app của bạn thay vì app chính thức. Hãy chọn standalone nếu quyền riêng tư là mục tiêu chính và người dùng chủ yếu sử dụng web app, hoặc nếu bạn sẵn sàng phát hành mobile app riêng. Hãy chọn đăng ký nếu push trên các app chính thức là yêu cầu bắt buộc. Sau này bạn có thể thay đổi lựa chọn trong Admin.
Khóa hệ thống trước khi cho phép người dùng truy cập
Rocket.Chat mặc định được phát hành với tính năng đăng ký mở, trong đó Registration Form được đặt là Public, vì vậy bất kỳ ai tìm thấy URL đều có thể tạo tài khoản. Trên một hostname công khai, đây là một lỗ hổng bảo mật. Hãy truy cập Admin → Settings → Accounts → Registration và đặt Registration Form thành Disabled để bạn có thể tự tạo tài khoản hoặc gửi link mời, hoặc đặt thành Secret URL. Trong khi ở đó, hãy tắt Allow Anonymous Read và Allow Anonymous Write trừ khi bạn thực sự muốn có một kênh công khai chỉ cho phép đọc. Nếu việc tạo thủ công từng tài khoản gây mất thời gian và đây không phải là dịch vụ duy nhất mà nhóm của bạn sử dụng, hãy trỏ tính năng đăng nhập OAuth của Rocket.Chat vào một server Authentik SSO tự host, nhờ đó việc quản lý người dùng mới và người dùng rời đi được thực hiện tập trung tại một nơi thay vì phải làm trên từng ứng dụng.
Bạn cũng cần quyết định nơi lưu trữ các tệp tải lên. Mặc định của File Upload là GridFS, lưu trữ mọi hình ảnh và tệp đính kèm ngay bên trong MongoDB. Cách này đơn giản, nhưng nó khiến cơ sở dữ liệu và mọi mongodump bạn thực hiện sẽ tăng dung lượng không giới hạn khi người dùng gửi ảnh chụp màn hình. Trong mục Admin → Settings → File Upload, bạn có thể chuyển bộ lưu trữ sang filesystem cục bộ hoặc một bucket tương thích với S3, đồng thời thiết lập kích thước tệp tối đa hợp lý. Nếu nhóm của bạn thường xuyên trao đổi toàn bộ thư viện ảnh thay vì chỉ thỉnh thoảng gửi ảnh chụp màn hình, những dữ liệu đó nên được lưu ở một server ảnh chuyên dụng thay vì trong cơ sở dữ liệu chat, và bài viết so sánh PhotoPrism và Immich sẽ giúp bạn cân nhắc chi phí RAM so với các lệnh backup cần thiết cho từng loại. Với một nhóm nhỏ, GridFS là đủ dùng; chỉ cần lưu ý rằng các bản backup của bạn sẽ ngày càng nặng hơn theo thời gian.
Sao lưu với mongodump
Toàn bộ dữ liệu của bạn nằm trong volume mongodb_data. Đừng chỉ sao chép volume khi database đang chạy, hãy thực hiện một bản dump nhất quán bằng mongodump, xuất trực tiếp ra một file trên host:
sudo docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > rocketchat-$(date +%F).archive.gzFile lưu trữ nén gzipped duy nhất đó là toàn bộ không gian làm việc của bạn: người dùng, kênh, tin nhắn, cài đặt và cả các file nếu bạn để upload trên GridFS. Nếu bạn đã chuyển các file upload sang filesystem hoặc S3, hãy sao lưu kho lưu trữ đó riêng biệt. Để khôi phục trên một stack mới, hãy khởi tạo replica set trước, sau đó chạy:
sudo docker compose exec -T mongodb mongorestore --archive --gzip --drop < rocketchat-2026-07-15.archive.gzHãy sao chép file lưu trữ ra khỏi máy chủ, lưu vào object storage, một server khác, bất cứ nơi nào mà nếu VPS bị hỏng thì bản sao lưu vẫn an toàn. Hãy chạy lệnh dump từ cron hàng đêm. Một bản sao lưu chưa từng được khôi phục chỉ là hy vọng, không phải là bản sao lưu thực sự; hãy thực hành khôi phục một lần trên một VPS dùng thử để đảm bảo nó hoạt động trước khi bạn thực sự cần đến.
Nâng cấp: cố định tag, đọc release notes, tuân thủ ma trận tương thích MongoDB
Có 2 quy tắc giúp việc nâng cấp diễn ra đơn giản. Trước hết, nâng cấp Rocket.Chat từng major version một. Rocket.Chat chạy schema migration khi boot. Tài liệu nâng cấp của Rocket.Chat yêu cầu luôn cập nhật tuần tự qua từng major version và cảnh báo rằng việc bỏ qua major version có thể gây ra lỗi tương thích nghiêm trọng. Đừng mặc định rằng phần mềm sẽ tự ngăn bạn: tài liệu của phần mềm không cam kết rằng việc nhảy thẳng từ 6.x lên 8.x sẽ bị từ chối an toàn. Nếu migration lỗi giữa chừng, lock của phần mềm vẫn còn và bạn phải sửa thủ công. Đổi image tag sang bản release mới nhất của major version kế tiếp, đọc release notes của bản release đó để kiểm tra các thay đổi breaking, chạy docker compose up -d và monitor log cho đến khi migration hoàn tất trước khi tiếp tục. Thứ hai, tuân thủ ma trận hỗ trợ của MongoDB. Mỗi bản release của Rocket.Chat hỗ trợ một tập phiên bản MongoDB cụ thể, và curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions cho bạn biết các phiên bản đó. Khi nâng cấp MongoDB, chẳng hạn từ 7.0 lên 8.0, hãy nâng từng major version một và đặt feature-compatibility version sau mỗi bước. Trên MongoDB 8.0, command đó yêu cầu chỉ định rõ confirm: true, nếu không command sẽ bị từ chối và hiển thị thông báo yêu cầu chạy lại với confirmation flag:
sudo docker compose exec mongodb mongosh --eval 'db.adminCommand({setFeatureCompatibilityVersion: "8.0", confirm: true})'Hãy tạo một mongodump trước mỗi lần nâng cấp một trong hai component. Đó là toàn bộ phương án dự phòng.
Các trường hợp lỗi và chuỗi lỗi chính xác
Rocket.Chat liên tục restart ngay sau docker compose up, và docker compose logs rocketchat đầy các MongoServerSelectionError. MongoDB đang chạy nhưng driver không chọn được primary, và chuỗi lỗi chính xác cho biết bạn đã cấu hình sai ở đâu. Server selection timed out after 30000 ms với topology type là ReplicaSetNoPrimary nghĩa là bạn chưa chạy rs.initiate(), nên replica set chưa có cấu hình. getaddrinfo ENOTFOUND theo sau là một hash ngẫu nhiên nghĩa là bạn đã initiate mà không dùng host: "mongodb:27017" cụ thể, nên MongoDB quảng bá một container hostname không thể phân giải. Chẩn đoán bằng sudo docker compose exec mongodb mongosh --eval 'rs.status()': nếu lệnh báo lỗi MongoServerError: no replset config has been received, hãy initiate replica set; nếu hiển thị một member có name là hash ngẫu nhiên, hãy initiate lại bằng service name.
Web UI tải được nhưng thao tác đăng nhập quay vô hạn và không hoàn tất. Mở browser console và bạn sẽ thấy WebSocket connection to 'wss://chat.example.com/websocket' failed. Đây gần như luôn là lỗi không khớp ROOT_URL hoặc do proxy không chuyển tiếp các upgrade header. Xác nhận ROOT_URL khớp chính xác với địa chỉ public, bao gồm cả https://, đồng thời block nginx location đặt Upgrade và Connection "upgrade" cùng với proxy_http_version 1.1. Sau khi thay đổi một trong các mục này, chạy lại docker compose up -d.
Một container liên tục bị dừng và docker compose ps cho thấy Restarting. docker compose logs bị ngắt giữa dòng và sudo dmesg | tail hiển thị Out of memory: Killed process 12345 (mongod) từ oom-killer; exit code là 137. Máy chủ đã hết RAM. Cách xử lý thực sự là dùng VPS lớn hơn, tối thiểu 4 GB. Tạm thời, hãy thêm swap và giới hạn cache của MongoDB bằng --wiredTigerCacheSizeGB trong command. Đặt giá trị thấp hơn mặc định, không phải cao hơn; ví dụ dùng 1 trên máy 4 GB (mặc định 1.5) hoặc 0.3 trên máy 2 GB (mặc định khoảng 0.5). Tuy nhiên, swap chỉ trì hoãn lần OOM tiếp theo khi có tải thực tế:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfiledocker compose up lỗi với Error response from daemon: driver failed programming external connectivity ... bind: address already in use. Một tiến trình đã chiếm port 3000, thường là container Rocket.Chat trước đó chưa dừng hoàn toàn hoặc một app khác. Tìm tiến trình đó bằng sudo ss -ltnp | grep :3000, dừng process hoặc container tương ứng, hoặc đổi phía host của mapping thành 127.0.0.1:3001:3000 rồi cập nhật proxy_pass của proxy cho khớp.
FAQ
Rocket.Chat có thực sự cần MongoDB replica set không?
Có, kể cả khi chỉ có một server với một database node. Rocket.Chat gửi message theo thời gian thực bằng MongoDB change streams. Change streams chỉ hoạt động với replica set; MongoDB standalone mongod không thể mở change stream. Bạn không cần nhiều máy. Chỉ cần chạy một MongoDB container bằng --replSet rs0 và khởi tạo replica set một member bằng rs.initiate(). Nếu bỏ qua bước này, driver sẽ không tìm thấy primary. Vì vậy Rocket.Chat sẽ restart-loop với MongoServerSelectionError: Server selection timed out và không bao giờ boot xong.
Rocket.Chat self-hosted cần bao nhiêu RAM?
Hãy chuẩn bị 4 GB cho mức tối thiểu thực tế và 8 GB cho team có tải cao. Node process của Rocket.Chat dùng khoảng 1 đến 1.5 GB. MongoDB WiredTiger cache mặc định chiếm một nửa tổng RAM trừ 1 GB, như thể không có tiến trình nào khác đang chạy trên máy. Trên máy 2 GB, cache đó, heap của Node và overhead riêng của mongod sẽ tranh chấp RAM. Out-of-memory killer sẽ terminate mongod khi có tải thực tế, ghi Killed vào log và trả về exit code 137. 2 GB chỉ đủ để đánh giá phần mềm với vài user thử nghiệm.
Làm cách nào để đặt Rocket.Chat phía sau HTTPS?
Chạy reverse proxy trên cùng VPS để thực hiện TLS termination và forward request đến 127.0.0.1:3000. Đặt ROOT_URL của container thành địa chỉ https:// public của bạn. Proxy phải forward các WebSocket upgrade header. Nếu không, quá trình đăng nhập sẽ bị treo. Certbot kết hợp với nginx là cách đơn giản nhất cho một app. Traefik phù hợp hơn nếu bạn chạy nhiều container phía sau một proxy và muốn tự động quản lý certificate.
Làm cách nào để backup Rocket.Chat self-hosted?
Tạo database dump nhất quán bằng mongodump thay vì copy volume: docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > backup.archive.gz. Archive đó chứa user, channel, message và setting, cùng các file đã upload nếu bạn vẫn lưu trữ bằng GridFS. Copy archive ra khỏi server. Tự động chạy backup mỗi đêm bằng cron. Sau đó thực hành mongorestore trên một máy dùng để thử nghiệm để xác nhận quy trình restore thực sự hoạt động.
Làm cách nào để upgrade Rocket.Chat mà không làm hỏng MongoDB?
Upgrade Rocket.Chat từng major version một. Rocket.Chat chạy migration khi boot. Tài liệu của Rocket.Chat cảnh báo rằng bỏ qua major version có thể gây lỗi tương thích nghiêm trọng, nhưng không đảm bảo sẽ ngăn bạn làm vậy. Đọc release note của từng phiên bản trước khi tăng pinned image tag. Kiểm tra các phiên bản MongoDB được release đích hỗ trợ bằng curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions. Khi upgrade MongoDB, cũng chuyển từng major version một và đặt setFeatureCompatibilityVersion bằng confirm: true sau mỗi lần chuyển. Luôn tạo mongodump trước.