Sizing the machine
The system requirements page gives two reference scenarios, each split between the Rocket.Chat process and MongoDB. Both are labelled minimums; the documentation says real needs depend on concurrent users and workload.
| Scenario (docs) | Component | Cores | Clock | Memory | Storage |
|---|---|---|---|---|---|
| Starter, no HA, up to 500 concurrent users | Rocket.Chat | 2 | 3.5-5.0 GHz | 4 GiB | 20 GiB |
| Starter, no HA, up to 500 concurrent users | MongoDB | 2 | 3.0 GHz | 4 GiB | 10 GiB |
| Commercial, Government, Defense (paid), HA, over 500 concurrent users | Rocket.Chat | 4 | 4.0-5.0 GHz | 8-12 GiB | 20 GiB |
| Commercial, Government, Defense (paid), HA, over 500 concurrent users | MongoDB | 2 | 3.0 GHz | 8-16 GiB | 20-80 GiB |
Both scenarios give MongoDB three replica-set members; on one machine we assume a single database copy, so any one-box total is our reading, not the docs'. The second scenario is the docs' high-availability tier for the paid Commercial, Government and Defense plans. Past 5,000 concurrent users the docs move to microservices on Kubernetes, which is a different project from one box. Two things the table leaves out matter on bare metal. First, attachments: by default they go into MongoDB through GridFS, which the docs advise against for production because it loads the database; they recommend S3-compatible object storage, which can be a MinIO server of your own. Second, the clock column is per core. Our sum, not the docs': the application row plus one MongoDB copy from the first scenario gives 4 cores, 8 GiB and 30 GiB on one host, so for the base install memory and disk are rarely the constraint on a dedicated machine (uploads aside); single-core speed is.
MongoDB: version and replica set
MongoDB is the one dependency you install and keep current yourself; the official image bundles Node.js. The support matrix pins versions per release line: 8.x needs 8.0 and above (verified with 8.2); 7.x ran on 6.0 and 7.0. A workspace on 7.x must move MongoDB to 8.0 before it upgrades to 8.x. The application connects with replicaSet=rs0 in its MONGO_URL, and the bundled compose.database.yml starts mongod --replSet and initiates a one-member set, so a single host works.
- One member is a replica set in name only. The docs strongly recommend three members for high availability; on one box a failed disk or kernel panic stops chat until it is back.
- The compose files pull the official
mongodb-community-serverimage (default tag 8.2-ubi8) and bind it to 127.0.0.1:27017. - The deploy guide warns that MongoDB 8.x may fail to start on Ubuntu 26.04 because of an upstream issue. Install Ubuntu 24.04 LTS.
BYPASS_MONGO_VALIDATION=trueskips the version check; the docs say it may break features or stop the server starting. Leave it unset.
Which machines fit
Every line on the dedicated server range is a whole machine with root, an unmetered port and no other tenant, which suits a chat server whose websocket connections stay open all day. Pick by core clock and RAM, then by city near your users.
- Small team, one service per box: the Intel Xeon E3-1585L v5 cartridge, 4 cores at 3 GHz, 16-64 GB, NVMe. It is the highest base clock in the cartridge range and one of the two cartridge models with an out-of-band console.
- More rooms, more uploads kept locally: the 16-core Intel Xeon D-1587 cartridge at 1.7 GHz, 16-128 GB, 1.92 TB NVMe. More cores, lower clock.
- Chat next to its object store, monitoring and backups: a dual-socket rack server such as 2 x Xeon E5-2630L v3, 16 cores, memory to 1 TB, and a management controller for console access.
- Several hosts for a three-member MongoDB set: order three machines in one city; they share our network, AS19624.
None of these base clocks reaches the 3.5 GHz in the docs' table. On a small workspace that shows up as response time per request, not as a hard ceiling; if latency matters, take the higher-clocked line. A racked machine is handed over in about 30 minutes once payment is approved; built-to-order lines take 4 to 24 hours.
Deploying with Docker Compose
The deploy guide uses the rocketchat-compose repository and drives everything from one .env file. Its Nginx path keeps Rocket.Chat on port 3000 behind a proxy. Several settings below are ours, not the guide's, and each is labelled. BIND_IP appears in neither the guide nor .env.example, but compose.yml reads it: it publishes the application port 3000 and the metrics port 9458 on ${BIND_IP:-0.0.0.0}, and Docker-published ports bypass ufw. With BIND_IP=127.0.0.1 both answer on IPv4 loopback only, with nothing on [::]. Turn the firewall on first, on a fresh Linux server running Ubuntu 24.04.
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
curl -L https://get.docker.com | sh
sudo apt install git nginx certbot
git clone --depth 1 https://github.com/RocketChat/rocketchat-compose.git
cd rocketchat-compose
cp .env.example .env
nano .env
# set, each on its own line:
# RELEASE=8.8.0 (a fixed release from the release notes)
# ROOT_URL=https://chat.example.com
# BIND_IP=127.0.0.1
# LETSENCRYPT_ENABLED=false
# TRAEFIK_PROTOCOL=http
sudo certbot certonly --standalone -d chat.example.com --email you@example.com \
--pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"
sudo docker compose -f compose.database.yml -f compose.yml -f compose.nats.yml up -d
sudo docker ps -a
Pin RELEASE to an exact version: the guide warns against latest in production. ROOT_URL=https://chat.example.com is ours: the guide's Nginx route leaves it at http://localhost, although its own table defines ROOT_URL as the full https address your users open. The certbot hooks are ours: the guide's standalone request needs port 80, which Nginx holds, so without them the automatic renewal fails. The three-file command is our trimmed version of the guide's (database, application, NATS); the guide's Nginx command also loads compose.monitoring.yml (Prometheus, Loki and Grafana) and docker.yml, which adds a healthcheck. If you add monitoring, change GRAFANA_ADMIN_PASSWORD from the sample value before the first start. Check docker ps -a: every service should be Up, with a MongoDB init container allowed to show Exited (0).
Claiming the admin account before going public
The setup wizard warns that the first person to complete its Admin Info step becomes the workspace admin. With Nginx not yet proxying, port 3000 answers only on loopback, so finish the wizard through a tunnel over your own SSH login: ssh -N -L 3300:127.0.0.1:3000 you@your-server, and browse to http://localhost:3300 on your workstation. The wizard then asks for organisation details and registers the workspace with Rocket.Chat Cloud, which mobile push, Marketplace apps and licence updates depend on.
The alternative in the docs is INITIAL_USER: yes with ADMIN_USERNAME, ADMIN_EMAIL and ADMIN_PASS set in compose.yml. That writes the admin password into a file in the repository checkout; if you use it, chmod 600 the file and remove the variables after the first start.
Nginx in front: websockets and TLS
Rocket.Chat clients hold a websocket, so the proxy must pass Upgrade and Connection headers, as the guide's config does. The version below follows it with four changes of ours: TLS 1.0 and 1.1 removed, IPv6 listeners added, client_max_body_size raised, since Nginx's 1 MB default rejects larger uploads before Rocket.Chat sees them, and X-Forwarded-Proto set to https where the guide sends http, because TLS ends at Nginx. Replace /etc/nginx/sites-available/default with it (the guide moves the original aside first), then sudo nginx -t and sudo systemctl restart nginx.
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name chat.example.com;
ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
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 $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
}
}
server {
listen 80;
listen [::]:80;
server_name chat.example.com;
return 301 https://$host$request_uri;
}
Backups, upgrades and the support window
- Backups: all workspace data lives in MongoDB, and the official
mongodb-community-serverimage ships the MongoDB database tools,mongodumpincluded. The guide's example callsdocker execon a container name; with no project name set, Compose names it after the folder (rocketchat-compose-mongodb-1). Ours goes through themongodbservice withdocker compose exec -Tinstead, so the name never matters, writes dated files underumask 077, and runs from cron because-Tasks for no terminal. Copy the dumps off the machine. - Restore: stop the
rocketchatservice first, then runmongorestore --drop --archivethrough the same service call. Without--drop, mongorestore only inserts and skips documents that already exist, so nothing changed since the dump is rolled back. - Upgrades: change
RELEASEin.envand rerunup -dwith every compose file you deployed with; leaving one out drops those services from the project. Dump the database first. - Support window: standard releases are supported for six months, LTS releases (from 7.10.x) for twelve. After that, the Push Gateway and Marketplace stop working for that version, so a server left alone loses mobile push.
- Outbound access: push goes through
gateway.rocket.chat; the server needs outbound HTTPS to it.
sudo install -d -m 700 /root/backups
sudo -i
cd /home/you/rocketchat-compose && umask 077 && docker compose -f compose.database.yml -f compose.yml -f compose.nats.yml exec -T mongodb mongodump --archive > /root/backups/chat-$(date +%F).dump
# restore: stop the app, replace the data with --drop, start the app again
cd /home/you/rocketchat-compose
docker compose -f compose.database.yml -f compose.yml -f compose.nats.yml stop rocketchat
docker compose -f compose.database.yml -f compose.yml -f compose.nats.yml exec -T mongodb mongorestore --drop --archive < /root/backups/chat-2026-10-23.dump
docker compose -f compose.database.yml -f compose.yml -f compose.nats.yml start rocketchat
# nightly, in root's crontab (crontab -e); cron needs % written as \%:
30 3 * * * cd /home/you/rocketchat-compose && umask 077 && docker compose -f compose.database.yml -f compose.yml -f compose.nats.yml exec -T mongodb mongodump --archive > /root/backups/chat-$(date +\%F).dump
Plan limits and when one box is the wrong answer
Every workspace deployed on 6.5 or later is provisioned as Starter: free, self-managed, many premium features, up to 50 users. At the limit the workspace cannot add users; existing users and data stay. Community is the MIT-licensed edition: up to 100 concurrent users, core messaging, Jitsi and BigBlueButton only, and 10,000 push notifications a month; Rocket.Chat describes it as suited to very basic, non-production use, not business-critical work. The paid plans (Commercial, Government, Defense) are quoted by Rocket.Chat's sales team; the legacy Pro plan closed to new purchases on 29 April 2026.
- Over 500 concurrent users, or a need for failover: plan the three-member MongoDB set across separate machines and a premium licence.
- Over 5,000 concurrent users: the docs specify microservices on Kubernetes; see our managed Kubernetes clusters.
- If you want federation with other organisations' servers rather than one workspace, compare our Matrix server notes.
Questions
Is self-hosted Rocket.Chat free?
Yes, within limits. A new workspace runs on Starter, which costs nothing and allows up to 50 users. Community, the MIT-licensed edition, allows up to 100 concurrent users with core messaging only and 10,000 push notifications a month, and Rocket.Chat positions it for very basic, non-production use rather than business-critical work. Beyond those, Rocket.Chat sells Commercial, Government and Defense plans through its sales team.
What happens when a Starter workspace reaches 50 users?
It can no longer add users. The documentation says existing users and data stay accessible, and an upgrade to a premium plan needs no data migration. You can also downgrade to Community, which Rocket.Chat describes as suited only to very basic, non-production use.
Can Rocket.Chat use a standalone MongoDB instead of a replica set?
The connection string in the official compose file names a replica set, replicaSet=rs0, and the bundled database container initiates one. On one server that set has a single member, which satisfies the requirement without giving any redundancy. For redundancy, the docs recommend three members.
Which ports does a self-hosted Rocket.Chat server expose?
Only 443 for HTTPS and 80 for the redirect to it, according to the system requirements. Port 3000 (the application), 27017 (MongoDB) and the monitoring ports stay internal. With Docker, make that true by binding them to 127.0.0.1, because published ports bypass ufw.
Do mobile push notifications work on a self-hosted workspace?
Yes, once the workspace is registered with Rocket.Chat Cloud and can reach gateway.rocket.chat over HTTPS. They stop if the server's version falls outside its support window, which is six months for a standard release and twelve for LTS.
How much disk does Rocket.Chat need?
The Starter scenario lists 20 GiB for the application and 10 GiB per MongoDB member, before uploads. Uploads go into MongoDB by default; the docs recommend object storage and estimate it from users, average upload size and months kept.