Rocket.Chat is a self-hosted Slack alternative that handles real-time messages, file uploads, and video calls. Without TLS, all of that is visible on the network. Rocket.Chat is a Node.js application that does not handle TLS natively in most deployment configurations — TLS is the responsibility of a reverse proxy in front of it. This article covers configuring nginx with TLS for Rocket.Chat, updating the ROOT_URL, enabling WebSocket proxying, and setting up Snap-based deployments.
Rocket.Chat deployment types
| Deployment | TLS approach |
|---|---|
Snap (rocketchat-server) | Caddy bundled in Snap handles TLS automatically |
| Docker / Docker Compose | nginx or Traefik as a sidecar |
| Manual Node.js install | nginx reverse proxy |
| Kubernetes (Helm) | Ingress controller with cert-manager |
The nginx approach covers both Docker and manual installs. The Snap approach is covered separately below.
Option A: nginx reverse proxy (manual / Docker install)
Step 1: Obtain a certificate
certbot certonly --standalone -d chat.example.com
Or if nginx is already running:
certbot certonly --webroot -w /var/www/html -d chat.example.com
Step 2: Configure nginx
Create /etc/nginx/sites-available/rocketchat:
upstream rocketchat {
server 127.0.0.1:3000;
keepalive 32;
}
server {
listen 80;
server_name chat.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
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;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
# Rocket.Chat uses long-polling and WebSockets
location / {
proxy_pass http://rocketchat;
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-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Required for long-polling (DDP / SockJS)
proxy_buffering off;
proxy_read_timeout 120s;
proxy_connect_timeout 15s;
proxy_send_timeout 120s;
proxy_cache off;
}
# Increase upload size limit
client_max_body_size 200M;
}
Enable and reload:
sudo ln -s /etc/nginx/sites-available/rocketchat /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Step 3: Set the ROOT_URL environment variable
Rocket.Chat uses the ROOT_URL environment variable (or ROCKETCHAT_URL in some Docker deployments) to generate all internal URLs. It must be the HTTPS URL.
For systemd / manual installs, edit the service file:
sudo systemctl edit rocketchat
[Service]
Environment=ROOT_URL=https://chat.example.com
Environment=PORT=3000
Environment=MONGO_URL=mongodb://localhost:27017/rocketchat
For Docker Compose, set in docker-compose.yml:
services:
rocketchat:
image: rocket.chat:latest
environment:
ROOT_URL: https://chat.example.com
PORT: "3000"
MONGO_URL: mongodb://mongo:27017/rocketchat
ports:
- "127.0.0.1:3000:3000"
Restart Rocket.Chat:
sudo systemctl restart rocketchat
# or
docker compose up -d rocketchat
Step 4: Update ROOT_URL via the admin panel
Rocket.Chat also stores ROOT_URL in its database. Update it via the admin panel:
- Log in as admin.
- Go to Administration → Settings → General.
- Update Site URL to
https://chat.example.com. - Click Save Changes.
If you cannot log in (URL mismatch preventing the UI from loading), update via MongoDB directly:
mongo rocketchat
db.rocketchat_settings.update({_id: 'Site_Url'}, {$set: {value: 'https://chat.example.com'}})
Or with mongosh:
mongosh rocketchat --eval 'db.rocketchat_settings.updateOne({_id: "Site_Url"}, {$set: {value: "https://chat.example.com"}})'
Option B: Snap deployment with automatic TLS
The Rocket.Chat Snap package includes Caddy as a reverse proxy and can obtain Let’s Encrypt certificates automatically.
Enable Caddy and Let’s Encrypt
# Set the domain
sudo rocketchat-server.caddy domains set chat.example.com
# Enable Caddy
sudo rocketchat-server.enable caddy
sudo systemctl restart snap.rocketchat-server.rocketchat-server
# Check Caddy logs
sudo journalctl -u snap.rocketchat-server.caddy -n 50
Caddy in the Snap will automatically request a Let’s Encrypt certificate for the domain and renew it without any additional configuration.
Update ROOT_URL for Snap
sudo snap set rocketchat-server siteurl=https://chat.example.com
sudo snap restart rocketchat-server
Docker Compose with Traefik
For Docker-based deployments, Traefik is a popular alternative to nginx:
version: '3.8'
services:
traefik:
image: traefik:v3.0
command:
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=admin@example.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik_letsencrypt:/letsencrypt
rocketchat:
image: rocket.chat:latest
environment:
ROOT_URL: https://chat.example.com
PORT: "3000"
MONGO_URL: mongodb://mongo:27017/rocketchat
labels:
- "traefik.enable=true"
- "traefik.http.routers.rocketchat.rule=Host(`chat.example.com`)"
- "traefik.http.routers.rocketchat.entrypoints=websecure"
- "traefik.http.routers.rocketchat.tls.certresolver=myresolver"
- "traefik.http.routers.rocketchat-http.rule=Host(`chat.example.com`)"
- "traefik.http.routers.rocketchat-http.entrypoints=web"
- "traefik.http.routers.rocketchat-http.middlewares=https-redirect"
- "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
- "traefik.http.services.rocketchat.loadbalancer.server.port=3000"
mongo:
image: mongo:6.0
command: mongod --replSet rs0
volumes:
traefik_letsencrypt:
WebSocket and long-polling configuration
Rocket.Chat uses DDP (Distributed Data Protocol) over WebSocket for real-time messaging. The nginx proxy must handle WebSocket upgrades correctly.
The critical nginx settings for Rocket.Chat:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_read_timeout 120s;
Without proxy_buffering off and proper WebSocket headers, users will experience frequent disconnections and “Rocket.Chat is not connected” banners.
Certificate renewal
sudo nano /etc/letsencrypt/renewal-hooks/deploy/rocketchat.sh
#!/bin/bash
# Reload nginx (Rocket.Chat itself does not need restarting)
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/rocketchat.sh
Verifying TLS and WebSocket connectivity
# Check HTTPS
curl -I https://chat.example.com
# Check certificate
openssl s_client -connect chat.example.com:443 -servername chat.example.com </dev/null 2>&1 \
| openssl x509 -noout -dates
# Test WebSocket upgrade
curl -I -H "Upgrade: websocket" -H "Connection: Upgrade" \
-H "Sec-WebSocket-Key: test" -H "Sec-WebSocket-Version: 13" \
https://chat.example.com/websocket
# Expected: HTTP/1.1 101 Switching Protocols
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| “Rocket.Chat is not connected” banner | WebSocket not proxied correctly | Add proxy_set_header Upgrade $http_upgrade to nginx |
| Login loop after TLS enabled | ROOT_URL still set to http:// | Update ROOT_URL env var and database Site_Url setting |
| File uploads fail | client_max_body_size too small in nginx | Set client_max_body_size 200M |
| Video calls not working | TURN/STUN behind TLS not configured | Configure WebRTC settings in Administration → Settings → Video Conference |
| OAuth callbacks fail | External auth callback URL uses http:// | Update OAuth application redirect URI to https:// |
Summary
Rocket.Chat HTTPS is configured entirely through a reverse proxy. Set ROOT_URL=https://chat.example.com in the environment and update the Site URL in the admin panel to match. The nginx configuration must enable WebSocket proxying (Upgrade header and proxy_buffering off) or users will constantly disconnect. For Snap deployments, Caddy handles TLS automatically with rocketchat-server.caddy domains set. Traefik with Docker Compose provides automatic Let’s Encrypt certificate management using container labels.