SSD Nodes Learn
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-07-24

Rocket.Chat zelf hosten met Docker Compose

Installeer Rocket.Chat op een VPS met Docker Compose. Leer waarom een MongoDB replica set vereist is en hoe u de juiste RAM-capaciteit voor uw server kiest.

Wat u bouwt

Een private teamchat die u volledig in eigendom heeft: Rocket.Chat draaiend op uw eigen VPS via Docker Compose, beveiligd met TLS, waarbij elk bericht wordt opgeslagen in een MongoDB-database die u kunt backuppen en verplaatsen. Rocket.Chat is een volwassen open-source alternatief voor Slack en Teams — met kanalen, directe berichten, threads, het delen van bestanden en spraak- en videobellen, volledig op hardware die u huurt en beheert. De applicatie is een enkele container die binnen enkele minuten is gestart. Eventuele fouten treden meestal op in de database; daarom richt deze handleiding zich voornamelijk op MongoDB. Hierbij is er één vereiste die gebruikers vaak verrast: Rocket.Chat werkt niet met een standalone MongoDB. Er is een replica set nodig, zelfs als die "set" uit slechts één node bestaat.

Vereisten en de RAM-berekening die niemand u vertelt

Kies een server met de juiste specificaties. De realistische ondergrens voor een klein team is 2 vCPU en 4 GB RAM. Het Node.js-proces van Rocket.Chat gebruikt alleen al ongeveer 1 tot 1,5 GB. De WiredTiger-cache van MongoDB gebruikt standaard ongeveer de helft van het resterende RAM-geheugen. Op een VPS met 2 GB starten beide processen zonder problemen, maar ze komen in conflict zodra er echt verkeer binnenkomt: de cache van MongoDB groeit, de heap van Node groeit, de kernel raakt zonder beschikbare pagina's en de out-of-memory killer beëindigt het grootste proces — meestal mongod. De container geeft Killed weer, Docker start deze opnieuw op, en u krijgt een chatserver die elke paar minuten uitvalt bij een belasting die hij normaal gesproken moeiteloos zou verwerken. 2 GB is voldoende voor testen met twee personen; het is geen server voor een team. Begin bij 4 GB. Gebruik 8 GB als u tientallen gelijktijdige gebruikers, videobellen of een groeiende uploadgeschiedenis verwacht.

U heeft ook drie zaken geregeld voordat u begint. Een domeinnaam met een A-record dat naar het publieke IP-adres van de VPS wijst — de real-time functies en mobiele clients van Rocket.Chat vereisen een stabiele hostname in plaats van een enkel IP-adres. Poorten 80 en 443 moeten openstaan in zowel de firewall van de server als de netwerkfirewall van uw provider (dit is een aparte instelling in de meeste beheerderspanelen). En een schone Ubuntu 24.04 KVM VPS met root- of sudo-rechten. Als u nog twijfelt of een chatserver de juiste eerste dienst is om te draaien, beschrijft de gids over wat het waard is om zelf te hosten in 2026 de afwegingen.

Installeer de Docker engine en de Compose plugin

Gebruik de eigen apt-repository van Docker. Gebruik niet het docker.io pakket van Ubuntu en niet de verouderde standalone docker-compose Python binary. Moderne Compose is een Docker plugin die u aanroept als docker compose — met een spatie in plaats van een koppelteken. De oude docker-compose v1 is end-of-life en verwerkt de onderstaande healthcheck- en dependency-syntax niet correct.

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

Controleer of beide onderdelen aanwezig zijn:

sudo docker version
sudo docker compose version

De controle is geslaagd als docker compose version iets weergeeft zoals Docker Compose version v2.x. Als er een foutmelding met docker: 'compose' is not a docker command verschijnt, is de plugin niet geïnstalleerd. Dit veroorzaakt later verwarrende fouten; los dit nu op.

Het compose-bestand: MongoDB als single-node replica set

Dit is het onderdeel waar gebruikers vaak fouten maken, lees dit daarom zorgvuldig. Rocket.Chat gebruikt MongoDB change streams om nieuwe berichten in real time naar verbonden clients te sturen. Change streams zijn alleen beschikbaar op een replica set. Als u Rocket.Chat verbindt met een standaard standalone mongod, zal de verbinding tot stand komen, maar zal het openen van een change stream mislukken. Hierdoor ontstaat een oneindige restart-loop. De oplossing is eenvoudig: u draait een gewone MongoDB-container, maar u start deze met --replSet en initialiseert daarna een set met één lid.

Maak een werkmap en een compose.yml aan:

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:

Enkele keuzes zijn bewust gemaakt. De Rocket.Chat-port is gepubliceerd op 127.0.0.1:3000 en niet op 0.0.0.0 — de applicatie zelf heeft geen TLS, dus alleen de reverse proxy op dezelfde machine mag deze bereiken. Het binden aan elke interface zou een plaintext inlogpagina direct op het publieke internet plaatsen. MongoDB is niet gepubliceerd op de host; deze is alleen bereikbaar via het interne netwerk van Compose onder de naam mongodb, wat precies de hostname is die de MONGO_URL gebruikt. MONGO_URL bevat ?replicaSet=rs0 — laat dit weg en de driver behandelt de server als standalone, zelfs als het een replica set is, waardoor change streams nog steeds falen. MONGO_OPLOG_URL verwijst naar de local database waar de oplog staat; moderne Rocket.Chat-versies geven de voorkeur aan change streams, maar het instellen hiervan is onschadelijk en voorkomt problemen bij oudere codepaden. De depends_on gebruikt condition: service_healthy, waardoor Compose wacht tot MongoDB op een ping reageert voordat Rocket.Chat wordt gestart — dit is de functie van de healthcheck.

Gebruik specifieke versie-tags voor beide images — mongo:8.0 en een expliciete Rocket.Chat-release zoals 8.5.1 in dit voorbeeld — en gebruik nooit :latest. Het gebruik van die tag verandert een geautomatiseerde docker pull in een onbedoelde upgrade die niet migreerbaar is. Controleer de huidige stabiele Rocket.Chat-release en de ondersteunde MongoDB-versies voordat u de versies vastzet. Rocket.Chat publiceert per release een machine-readable informatiebestand: curl -s https://releases.rocket.chat/8.5.1/info | jq '{compatibleMongoVersions, lts}' geeft compatibleMongoVersions: ["8.0"] terug voor 8.5.1, dus mongo:8.0 is de enige ondersteunde engine, plus een lts flag die aangeeft of die release een long-term-support build is die het waard is om vast te zetten voor een server die u liever niet handmatig hoeft te beheren.

Initialiseer de replica set

Start de stack:

sudo docker compose up -d

Rocket.Chat zal direct crashen en Docker zal de container blijven herstarten — dit is het verwachte gedrag, omdat de replica set nog niet bestaat. Maak deze handmatig aan:

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

Een correct resultaat is { ok: 1 }. Binnen enkele seconden kiest de enkele node zichzelf als primary; bevestig dit met:

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

U dient PRIMARY te zien. Het belangrijkste detail op deze pagina is het argument host: "mongodb:27017". Als u een enkele rs.initiate() uitvoert zonder lijst met leden, adverteert MongoDB de replica set onder de interne hostname van de container — een willekeurige hash zoals a1b2c3d4e5f6. Rocket.Chat kan deze naam niet resolven omdat de verbinding vanuit de eigen container komt. Hierdoor faalt de MongoDB-driver op DNS en blijft de container in een loop loggen met MongoServerSelectionError: getaddrinfo ENOTFOUND a1b2c3d4e5f6. Gebruik altijd de expliciete servicenaam die overeenkomt met uw MONGO_URL.

Eerste boot: monitor het opstartproces

Zodra de set de primary is, maakt de volgende herstart van Rocket.Chat een succesvolle verbinding. De eerste migraties worden gestart. Volg de logs:

sudo docker compose logs -f rocketchat

De regel waar u op wacht is de startup banner:

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

De eerste boot duurt langzaam — de applicatie voert database migraties uit en bouwt indexes op. Geef het proces een of twee minuten de tijd voordat u actie onderneemt. Als de log in plaats daarvan MongoServerSelectionError: Server selection timed out after 30000 ms herhaalt met een topology description van type ReplicaSetNoPrimary, dan is de replica set niet geïnitialiseerd. Als de log getaddrinfo ENOTFOUND herhaalt op een willekeurige hash, dan is de set geïnitialiseerd met de verkeerde host. In beide gevallen moet u een stap teruggaan. Zodra u SERVER RUNNING ziet, luistert Rocket.Chat op 127.0.0.1:3000. Het is dan tijd om een echte hostname en TLS toe te voegen.

Gebruik TLS

Expose Rocket.Chat nooit via plain HTTP. Als u eenmaal inlogt via http://, geeft u uw admin-wachtwoord aan iedereen op het netwerkpad. Gebruik TLS via een reverse proxy op dezelfde machine en stuur het verkeer door naar 127.0.0.1:3000. Twee zaken zijn van belang: de proxy moet de WebSocket upgrade headers doorsturen, omdat Rocket.Chat real-time is en zonder deze headers niet werkt, en de ROOT_URL van de container moet exact overeenkomen met het publieke HTTPS-adres dat gebruikers invoeren.

Begin met een plain HTTP nginx server block die proxyt naar de app en de upgrade headers doorstuurt. Sla dit op als /etc/nginx/sites-available/rocketchat, maak een symlink naar sites-enabled en 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;
    }
}

Gebruik voor nu poort 80 — een block met listen 443 ssl; zonder certificaat zal sudo nginx -t niet eens passeren. Reload nginx (sudo nginx -t && sudo systemctl reload nginx) en vraag daarna het certificaat aan. De eenvoudigste methode op Ubuntu is Let's Encrypt TLS certificates with Certbot and nginx: certbot --nginx herschrijft het bovenstaande block ter plaatse. Hierbij worden listen 443 ssl;, de ssl_certificate regels en een automatische 80-naar-443 redirect toegevoegd, en wordt de vernieuwing automatisch gepland. Als u al meerdere containers achter één proxy draait, is Traefik with automatic TLS for many Docker apps de nettere optie — voeg router en service labels toe aan de rocketchat service en Traefik regelt de aanvragen en de certificaatvernieuwing zonder nginx block. In beide gevallen moet u ROOT_URL op https://chat.example.com zetten in compose.yml en sudo docker compose up -d opnieuw uitvoeren, zodat de container de wijziging overneemt. Als u wilt dat de server alleen bereikbaar is via uw eigen netwerk in plaats van het publieke internet, gebruik dan een self-hosted WireGuard VPN on the VPS en bind de proxy aan het tunnel-adres.

De installatiewizard voor de eerste keer

Navigeer naar https://chat.example.com en Rocket.Chat leidt u door een korte wizard. Begin bij het admin account — een echte naam, gebruikersnaam, e-mailadres en een sterk wachtwoord; dit is het enige account dat bestaat, dus verlies dit niet. Vervolgens de organisation and server info — naam, sector, grootte, de sitenaam en de standaardtaal; dit is cosmetisch, vul het in en ga verder. Daarna volgt de keuze die er echt toe doet: deze workspace register with Rocket.Chat Cloud of houd deze standalone.

Registratie maakt mobiele pushmeldingen mogelijk via de gateway van Rocket.Chat en de add-on marketplace. Dit vereist een verbinding met de cloud van Rocket.Chat. Bij een standalone installatie blijft de server volledig privé en onafhankelijk. Echter, pushmeldingen op iOS en Android werken dan niet meer, omdat Apple en Google het niet toestaan dat een zelfgebouwde app de push-certificaten beheert — de officiële apps maken gebruik van de cloud gateway. Kies voor standalone als privacy het hoofddoel is en uw gebruikers de webapp gebruiken; kies voor registratie als mobiele pushmeldingen essentieel zijn. U kunt deze keuze later wijzigen onder Admin.

Beperk de toegang voordat u gebruikers uitnodigt

Rocket.Chat is standaard ingesteld op open registration on. Het Registration Form staat standaard op Public. Hierdoor kan iedereen met de URL een account aanmaken. Dit is een beveiligingsrisico op een publieke hostname. Ga naar Admin → Settings → Accounts → Registration en wijzig Registration Form naar Disabled om accounts handmatig of via een uitnodigingslink aan te maken, of naar Secret URL. Schakel Allow Anonymous Read en Allow Anonymous Write uit, tenzij u specifiek een publiek kanaal met alleen-lezen rechten wilt.

Bepaal ook waar uploads worden opgeslagen. De standaard File Upload opslag is GridFS. Hierbij worden elke afbeelding en bijlage binnen MongoDB zelf opgeslagen. Dit is eenvoudig, maar het betekent dat uw database — en elke mongodump die u maakt — onbeperkt groeit doordat gebruikers screenshots plakken. Onder Admin → Settings → File Upload kunt u de opslag wijzigen naar het lokale filesystem of een S3-compatibele bucket. U kunt hier ook een redelijke maximale bestandsgrootte instellen. Voor een klein team is GridFS geschikt; houd er rekening mee dat uw backups na verloop van tijd groter worden.

Backups met mongodump

Al uw gegevens staan op het mongodb_data volume. Kopieer het volume niet simpelweg terwijl de database draait. Maak een consistente dump met mongodump en stuur deze naar een bestand op de host:

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

Dit enkele gzipped archief bevat uw volledige workspace: gebruikers, kanalen, berichten, instellingen en — indien u uploads op GridFS laat staan — ook de bestanden. Als u uploads naar het filesystem of S3 heeft verplaatst, maak dan een aparte backup van die opslag. Herstel de gegevens op een nieuwe installatie door eerst de replica set te initialiseren, en voer daarna uit:

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

Kopieer het archief naar een externe locatie — object storage, een andere server, of een plek waar de backup niet verloren gaat als de VPS uitvalt — en voer de dump elke nacht uit via cron. Een backup die u nooit heeft hersteld, is slechts een hoopje hoop en geen echte backup. Oefen het herstellen eenmalig op een tijdelijke VPS, zodat u zeker weet dat het werkt voordat u het echt nodig heeft.

Upgrades: pin tags, lees de notes, volg de Mongo matrix

Twee regels zorgen voor een probleemloos upgradeproces. Ten eerste: upgrade Rocket.Chat met telkens één major versie tegelijk. Het systeem voert schema migrations uit tijdens het opstarten. Het weigert bewust om direct naar een volgende major versie te springen; een sprong van 6.x naar 8.x veroorzaakt een migration error in plaats van dat de data corrupt raakt. Pas de image tag aan naar de laatste release van de volgende major versie, lees de release notes voor breaking changes, voer docker compose up -d uit, en controleer in de logs of de migratie is voltooid voordat u verdergaat. Ten tweede: volg de MongoDB support matrix. Elke Rocket.Chat release ondersteunt een specifieke set MongoDB versies; curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions geeft aan welke versies dit zijn. Wanneer u MongoDB update — bijvoorbeeld van 7.0 naar 8.0 — doe dit dan stap voor stap per major versie. Stel na elke stap de feature-compatibility version in. Op MongoDB 8.0 vereist dit commando een expliciete confirm: true, anders geeft het systeem een foutmelding met het verzoek om het commando opnieuw uit te voeren met de confirmation flag:

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

Maak een mongodump voordat u een van beide componenten upgrade. Dit is uw enige verzekering.

Foutmodi, met de exacte strings

Rocket.Chat start-loops direct na docker compose up, en docker compose logs rocketchat vult met een MongoServerSelectionError. MongoDB draait, maar de driver kan geen primary selecteren. De exacte string geeft aan welke fout is gemaakt. Server selection timed out after 30000 ms met een topology type van ReplicaSetNoPrimary betekent dat u rs.initiate() nooit heeft uitgevoerd — de set heeft nog geen configuratie. getaddrinfo ENOTFOUND gevolgd door een willekeurige hash betekent dat u de initiatie heeft gestart zonder de expliciete host: "mongodb:27017", waardoor MongoDB een onoplosbare container-hostname adverteert. Diagnoseer met sudo docker compose exec mongodb mongosh --eval 'rs.status()': als er een fout MongoServerError: no replset config has been received optreedt, initialiseer de set; als een lid wordt getoond waarvan de name een willekeurige hash is, initialiseer opnieuw met de servicenaam.

De web UI laadt, maar het inloggen blijft oneindig draaien. Open de browserconsole; u ziet daar WebSocket connection to 'wss://chat.example.com/websocket' failed. Dit is bijna altijd een ROOT_URL mismatch of een proxy die de upgrade headers niet doorstuurt. Controleer of ROOT_URL gelijk is aan het exacte publieke adres inclusief https://, en of uw nginx location block Upgrade en Connection "upgrade" instelt met proxy_http_version 1.1. Pas een van beide aan en voer docker compose up -d opnieuw uit.

Een container stopt voortdurend met draaien en docker compose ps geeft aan dat deze Restarting is. docker compose logs wordt halverwege afgebroken en sudo dmesg | tail toont Out of memory: Killed process 12345 (mongod) van de oom-killer; de exit code is 137. Het systeem heeft onvoldoende RAM. De definitieve oplossing is een grotere VPS — minimaal 4 GB. Gebruik als tijdelijke oplossing swap en beperk de cache van MongoDB met --wiredTigerCacheSizeGB 1 in de command, maar swap stelt de volgende OOM onder echte belasting slechts uit:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

docker compose up faalt met Error response from daemon: driver failed programming external connectivity ... bind: address already in use. Een proces gebruikt al poort 3000 — vaak een eerdere Rocket.Chat container die niet netjes is gestopt, of een andere applicatie. Zoek dit proces met sudo ss -ltnp | grep :3000, stop het proces of de container, of wijzig de host-zijde van de mapping naar 127.0.0.1:3001:3000 en pas de proxy_pass van uw proxy aan.

FAQ

Heeft Rocket.Chat echt een MongoDB replica set nodig?

Ja, zelfs voor een enkele server met één database-node. Rocket.Chat verstuurt berichten in real time via MongoDB change streams. Change streams zijn alleen beschikbaar in een replica set; een standalone mongod kan deze niet openen. U heeft geen meerdere machines nodig; u gebruikt één MongoDB container gestart met --replSet rs0 en initialiseert een set met één lid met rs.initiate(). Als u deze stap overslaat, vindt de driver nooit een primary. Hierdoor blijft Rocket.Chat in een restart-loop hangen met MongoServerSelectionError: Server selection timed out en wordt het opstartproces nooit voltooid.

Hoeveel RAM heeft self-hosted Rocket.Chat nodig?

Reken op 4 GB als praktisch minimum en 8 GB voor een actief team. Het Node-proces van Rocket.Chat gebruikt ongeveer 1 tot 1.5 GB. MongoDB claimt ongeveer de helft van het resterende RAM voor de WiredTiger cache. Op een systeem met 2 GB ontstaat er een conflict en zal de out-of-memory killer mongod beëindigen bij enige belasting. Dit resulteert in Killed in de logs en exit code 137. 2 GB is alleen voldoende om de software te testen met enkele testgebruikers.

Hoe plaats ik Rocket.Chat achter HTTPS?

Draai een reverse proxy op dezelfde VPS die TLS termineert en het verkeer doorstuurt naar 127.0.0.1:3000. Stel de ROOT_URL van de container in op uw publieke https:// adres. De proxy moet de WebSocket upgrade headers doorsturen, anders blijft de login hangen. Certbot met nginx is de eenvoudigste setup voor één applicatie; Traefik is efficiënter als u meerdere containers achter één proxy draait en automatische certificaatbeheer wilt.

Hoe maak ik een back-up van self-hosted Rocket.Chat?

Maak een consistente database dump met mongodump in plaats van het volume te kopiëren: docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > backup.archive.gz. Dit archief bevat gebruikers, kanalen, berichten en instellingen, plus geüploade bestanden als de opslag op GridFS staat. Kopieer het bestand naar een andere server, automatiseer dit dagelijks met cron, en oefen een mongorestore op een testmachine zodat u zeker weet dat herstel daadwerkelijk werkt.

Hoe upgrade ik Rocket.Chat zonder MongoDB te beschadigen?

Upgrade Rocket.Chat telkens met één major versie tegelijk. De software voert migraties uit tijdens het opstarten en staat het overslaan van major versies niet toe. Lees de release notes van elke versie voordat u de pinned image tag aanpast. Controleer welke MongoDB-versies uw doelversie ondersteunt met curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions. Wanneer u MongoDB upgrade, doe dit dan stap voor stap per major versie en stel setFeatureCompatibilityVersion in met confirm: true na elke stap. Maak altijd eerst een mongodump.