Skip to Content

Production Guide: Deploy Rocket.Chat with Docker Compose + Caddy + MongoDB on Ubuntu

Self-host the leading open-source team chat platform with automatic HTTPS, persistent storage, and production-grade operations.

Teams that rely on Slack or Microsoft Teams are one pricing change away from a disruption. Rocket.Chat is the leading open-source team communication platform — supporting channels, threads, direct messages, voice and video calls, bots, and REST/WebSocket APIs — and running it on your own infrastructure gives you full control over data residency, compliance policies, and integrations. This guide walks through a production-ready deployment of Rocket.Chat using Docker Compose for container orchestration, Caddy as the TLS-terminating reverse proxy, and MongoDB as the persistent backend.

You will end up with a hardened, publicly accessible Rocket.Chat instance with automatic HTTPS, persistent data volumes, systemd process supervision, and the operational hygiene needed for a real team deployment.

Architecture and flow overview

The stack has three layers. Caddy sits at the edge, listening on ports 80 and 443. It provisions a Let's Encrypt certificate automatically, strips TLS, and forwards plain HTTP to the Rocket.Chat container on the internal Docker network. Rocket.Chat itself is the application tier: it manages all chat state, user accounts, integrations, and real-time WebSocket connections. MongoDB is the persistence tier, running as a replica set (even with one node) because Rocket.Chat's change streams and oplog tailing require replica-set mode.

All three services run in a shared Docker Compose network. Caddy is the only container that binds ports on the host (80/443). MongoDB and Rocket.Chat are fully internal. Volumes are named Docker volumes, making snapshot and migration straightforward.

Prerequisites

  • Ubuntu 22.04 LTS (or 24.04) VPS with at least 2 vCPU and 2 GB RAM (4 GB recommended for teams over 25 users)
  • A domain name pointed at your server's public IP via an A record (e.g., chat.example.com)
  • Docker Engine 24+ and Docker Compose v2 installed (apt install docker.io docker-compose-v2)
  • UFW configured to allow ports 22, 80, and 443
  • A non-root sudo user for operations

Step-by-step deployment

1. Create the project directory and environment file

mkdir -p /opt/rocketchat && cd /opt/rocketchat
cat > .env << 'EOF'
ROOT_URL=https://chat.example.com
MONGO_URL=mongodb://mongo:27017/rocketchat?replicaSet=rs0
MONGO_OPLOG_URL=mongodb://mongo:27017/local?replicaSet=rs0
PORT=3000
DEPLOY_METHOD=docker
EOF

Replace chat.example.com with your actual domain. The MONGO_URL and MONGO_OPLOG_URL use the Docker network service name mongo — no host-level port exposure needed.

2. Write the Docker Compose file

version: "3.8"

services:
  mongo:
    image: mongo:6.0
    restart: unless-stopped
    volumes:
      - mongo_data:/data/db
      - mongo_config:/data/configdb
    command: >
      mongod
      --replSet rs0
      --oplogSize 128
    networks:
      - internal

  mongo-init-replica:
    image: mongo:6.0
    restart: on-failure
    depends_on:
      - mongo
    command: >
      bash -c "sleep 5 && mongosh --host mongo:27017 --eval
      'rs.initiate({_id:\"rs0\",members:[{_id:0,host:\"mongo:27017\"}]})
       .then(() => quit(0)).catch(() => quit(0))'"
    networks:
      - internal

  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:7.4
    restart: unless-stopped
    env_file: .env
    depends_on:
      - mongo
    volumes:
      - rocketchat_uploads:/app/uploads
    networks:
      - internal
      - web

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - web

volumes:
  mongo_data:
  mongo_config:
  rocketchat_uploads:
  caddy_data:
  caddy_config:

networks:
  internal:
  web:

3. Write the Caddyfile

chat.example.com {
    reverse_proxy rocketchat:3000 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        -Server
    }

    log {
        output file /data/logs/access.log {
            roll_size 50mb
            roll_keep 5
        }
    }
}

4. Start the stack

cd /opt/rocketchat
docker compose up -d
# Watch startup logs
docker compose logs -f rocketchat

On first boot, MongoDB initialises the replica set via the mongo-init-replica one-shot container. Rocket.Chat then connects and runs its database migrations. The first boot usually takes 60–90 seconds.

5. Create the admin account

Navigate to https://chat.example.com in a browser. The setup wizard will prompt you to create the first admin user. Complete the wizard — you can skip federation and cloud registration for self-hosted deployments.

Configuration and secrets handling

Sensitive values should not live in the Compose file. Keep them in the .env file with restricted permissions and exclude it from version control:

chmod 600 /opt/rocketchat/.env
echo ".env" >> /opt/rocketchat/.gitignore

For production teams, rotate the MongoDB connection string by updating .env and running docker compose up -d --force-recreate rocketchat. If you add a MongoDB username and password later, update both MONGO_URL and MONGO_OPLOG_URL to include credentials: mongodb://rcuser:strongpass@mongo:27017/rocketchat?replicaSet=rs0&authSource=rocketchat.

For SMTP (email notifications), set these additional variables in .env:

MAIL_URL=smtp://user:[email protected]:587

All admin-configurable options (LDAP, OAuth, push notifications, file storage providers) live under Administration → Settings in the Rocket.Chat UI and are stored in MongoDB — no config-file editing required after initial deployment.

Verification

# All containers running
docker compose ps

# MongoDB replica set confirmed
docker compose exec mongo mongosh --eval "rs.status().ok"
# Expected: 1

# Rocket.Chat health endpoint
curl -sf https://chat.example.com/health | python3 -m json.tool
# Expected: {"status":"healthy",...}

# TLS certificate valid
curl -sv --head https://chat.example.com 2>&1 | grep -E "(SSL|HTTP)"

Log in as the admin user, send a test message in the #general channel, and confirm the message persists across a container restart (docker compose restart rocketchat).

Common issues and fixes

MongoDB not in replica set mode: Rocket.Chat refuses to start and logs MongoError: Change Stream requires the 'majority' read concern. Confirm rs.status().ok === 1 from inside the mongo container. If the init container exited too early, re-run it: docker compose run --rm mongo-init-replica.

Caddy certificate provisioning fails: Caddy requires ports 80 and 443 to be reachable from the internet for the ACME challenge. Check UFW (ufw status), verify your domain A record propagated (dig +short chat.example.com), and check Caddy logs (docker compose logs caddy). Caddy rate-limits are per Let's Encrypt — if you exceeded them during testing, add tls internal temporarily to use a self-signed cert.

WebSocket connections dropping after a load balancer/proxy: Caddy handles WebSocket upgrade automatically, but some upstream proxies strip Upgrade headers. Add header_up Connection "Upgrade" and header_up Upgrade {http.request.header.Upgrade} to the reverse_proxy block if users see "real-time connection lost" banners.

File uploads fail or return 413: Caddy's default max request body is generous, but Rocket.Chat also enforces its own limit under Administration → File Upload → Maximum File Size. Increase it there and add request_body { max_size 100MB } to the Caddy site block if needed.

Container memory pressure: MongoDB and Rocket.Chat together consume roughly 800 MB at idle. If you see OOM kills, add memory limits to the Compose services or upgrade to a 4 GB instance. You can also tune WiredTiger cache: --wiredTigerCacheSizeGB 0.5 in the MongoDB command.

FAQ

Can I migrate an existing Rocket.Chat instance to this deployment?

Yes. Export your existing MongoDB data with mongodump --archive=rc_backup.gz --gzip, copy the archive to the new host, and restore it with mongorestore --archive=rc_backup.gz --gzip --drop after the new stack is up but before creating admin. Match the Rocket.Chat version between old and new instances to avoid migration errors.

How do I enable LDAP or Active Directory authentication?

Navigate to Administration → LDAP and enable the integration. Fill in your LDAP server address, bind DN, bind password, and user search base. Rocket.Chat supports both LDAP and SAML 2.0 (available under Administration → SAML). You do not need to modify the Docker Compose file — all auth configuration is stored in MongoDB and managed through the UI.

How do I upgrade Rocket.Chat?

Change the image tag in docker-compose.yml (e.g., 7.4 to 7.5), pull the new image, and recreate the container: docker compose pull rocketchat && docker compose up -d rocketchat. Rocket.Chat auto-runs database migrations on startup. Always take a mongodump backup before upgrading.

Can multiple instances share the same MongoDB for high availability?

Yes, but you need at minimum a 3-node MongoDB replica set and a load balancer in front of your Rocket.Chat containers. For teams under 500 users, a single-node deployment with daily backups and a restart policy is typically sufficient. Scale horizontally only when you observe sustained >80% CPU on the Rocket.Chat container.

How do I set up push notifications for mobile apps?

Rocket.Chat Cloud provides a free push notification gateway (15,000 pushes/month). Register your workspace under Administration → Connectivity Services → Connect to Cloud, then enable push notifications under Administration → Push. Self-hosted push delivery requires setting up your own Firebase (Android) and APNs (iOS) credentials, which is complex — the Cloud gateway is the practical choice for most deployments.

How do I back up Rocket.Chat data?

Back up two things: the MongoDB data volume and the uploads volume. For MongoDB: docker compose exec mongo mongodump --archive=/tmp/rc_backup.gz --gzip && docker compose cp mongo:/tmp/rc_backup.gz ./rc_backup.gz. For uploads: docker run --rm -v rocketchat_uploads:/uploads -v $(pwd):/backup busybox tar czf /backup/uploads.tar.gz /uploads. Store both archives off-site (S3, Backblaze B2). Automate with a daily cron job.

Internal links

Talk to us

If you want this deployed with hardened access controls, monitoring standards, and production runbooks tailored to your environment, our team can help end-to-end.

Contact Us

Production Guide: Deploy Strapi with Docker Compose + Caddy + PostgreSQL on Ubuntu
Self-host your headless CMS with automatic HTTPS, environment-variable secrets, and a repeatable upgrade path