Rocket.Chat

Rocket.Chat ist eine Workstream Collaboration Platform (WSC) und damit eine freie Alternative zu Slack und MS Teams. Es basiert auf Node.js. Da Node.js „single threaded“ ist, kann Rocket.Chat nicht von mehreren CPU-Cores profitieren. Bei vielen Concurrent Users kann Rocket.Chat daher träger reagieren, ein Core wird dann zu 100% durch Node.js ausgelastet. In dem Fall lässt sich Rocket.Chat in mehreren Instanzen betreiben.

Rocket.Chat legt die Inhalte (Chat-Nachrichten, Raum-Konfigurationen etc.) in einer MongoDB ab.

Wichtig seit v6.0:

  • Die Rocket.Chat Community Edition ist für den Einstieg gedacht, aber NICHT für den produktiven Einsatz in grossen Unternehmen.

  • Version 6.0 bringt deshalb Änderungen im Registrierungsprozess, um die Registrierungsrate zu erhöhen.

  • Nicht registrierte Workspaces haben keinen Zugang zu Push-Benachrichtigungen, Gateway-Diensten oder dem Marketplace.

Was sind die Einschränkungen der Community-Edition? (Stand 2025-11-26)

  • Maximal 5 Apps aus dem Marketplace installierbar, keine privaten Apps möglich (Community workspaces can enable up to 5 marketplace apps. Private apps can only be enabled in premium plans.)

  • Maximal 10’000 Push-Nachrichten pro Monat

  • Maximal 200 concurrent Sessions (Total concurrent connections. A single user can be connected multiple times. User presence service is disabled at 200 or more to prevent performance issues.)

  • Keine selbst-definierten Gruppen möglich

Was bringt die Enterprise-Variante?

  • Infrastructure: High Scalability

  • Administration: Features wie LDAP/Active Directory, > 10K Push Notifications, Federation

  • Security: Secured Push Notifications, Message Audit Panel, Data Loss Prevention

  • Support: Support from Rocket.Chat

  • Advanced Team Collaboration: Engagement Dashboard (Data-driven decisions), Read Receipt

  • Advanced Omnichannel Customer Engagement: On-Hold Queues, Queue Waiting Time, Concurrent Chat Limit, Canned Responses, Advanced Queue Monitoring

Konzepte

Channel („#“)

Channels sind Chaträume. Meist werden Channels themenbezogen organisiert.

Channels („Rooms“) können Threads, Discussions und Benutzer (Members) enthalten.

Ein Channel kann nur einem Team zugeordnet werden.

Wird ein Channel-Member entfernt, bleiben seine Nachrichten erhalten.

Team

Ein Team ist eine Sammlung von Channels, die einem bestimmten Zweck, Kunden oder Projekt dienen. Tritt ein neues Mitglied dem Team bei, erhält es automatisch Zugang zu allen Channels, bei denen im Team der Haken „Auto-join“ gesetzt ist. So muss man Mitglieder nicht einzeln zu jedem Channel hinzufügen.

Teams können Channels, Threads, Discussions und Team Members beinhalten. In Teams kann auch gechattet werden.

Ein Team kann nur Benutzer, aber keine anderen Teams als Members beinhalten. Interessanterweise kann der zentrale Admin-Account keinem Team als Member zugeordnet werden. Wird ein Benutzer einem Team hinzugefügt, sieht er nur das Team, falls die angehängten Channels keinen Auto-join haben. Wird ein Team-Member entfernt, wird gefragt, aus welchen Channels der Benutzer, in denen er Mitglied ist, ebenfalls entfernt werden soll. Seine Nachrichten im Team bleiben erhalten.

Wird ein Channel erstellt, erbt dieser die Team-Members ohne aktiviertes Auto-join nicht - egal ob der Channel zuerst erstellt und später hinzugefügt wird, oder direkt im Team. Wurden Team-Members per Auto-join hinzugefügt, und der Auto-join später deaktiviert, bleiben die Benutzer dem Channel zugeordnet.

Diskussionen

Diskussionen ermöglichen es, grössere Themen innerhalb eines Teams oder Channels zu diskutieren (sie müssen also zu einem übergeordneten Team oder Channel gehören).

Wird eine neue Discussion erstellt, wird nach dem „Parent Channel or Group“ (gemeint ist Team) gefragt. Discussions können nur mit Admin-Rechten erstellt werden. Wird die Discussion in einem Channel mit Auto-join erstellt und ohne Member-Angabe, erhalten Team Member den Hinweis, dass es eine neue Diskussion gibt. Sie können dann per Klick auf „Join“ selbst entscheiden, ob sie an der Diskussion teilnehmen möchten.

Wird ein Discussion-Member entfernt, bleiben seine Nachrichten erhalten.

Benutzer

Neu angelegte Benutzer sehen (auch über die Suche) nur die Teams, Channels, Diskussionen und andere Benutzer, über die sie zugeteilt wurden.

Benutzer dürfen nur „Direct Messages“ erstellen.

Werden Benutzer per @ in Teams, Channels oder Discussions erwähnt (= „mention“), zu denen sie nicht gehören, erhalten sie die Nachricht nicht.

Wird ein Benutzer in Rocket.Chat gelöscht, werden alle Nachrichten des Benutzers aus allen Objekten entfernt. Daher sollten Benutzer deaktiviert statt gelöscht werden, wenn man auf eine konsistente Chat-History Wert legt. Wird ein Benutzer deaktiviert, wird er sofort ausgeloggt.

Beispiel

Man hat ein technisches Team und unter diesem Team einen Channel mit dem Namen „Website-Entwicklung“ erstellt. Die Gespräche über jede Funktion der Website können in Diskussionen untergebracht werden.

Installation

Rocket.Chat wird offiziell als Docker-Image verteilt. Auf RHEL läuft das rootless mit Podman. Ein Setup besteht aus zwei Containern: einer MongoDB (zwingend als Replica Set, das setzt Rocket.Chat voraus) und Rocket.Chat selbst. Davor gehört ein Reverse Proxy mit TLS (siehe Betrieb hinter Reverse Proxy).

Die Versionen von Rocket.Chat und MongoDB müssen zueinander passen, siehe die MongoDB-Support-Matrix in der Rocket.Chat-Dokumentation.

# set to the desired Rocket.Chat release and a compatible MongoDB version
RC_VERSION='7.0.0'
MONGODB_VERSION='8.0'

podman network create rocketchat

MongoDB als Single-Node-Replica-Set starten und das Replica Set einmalig initialisieren:

podman run \
    --detach \
    --name rocketchat-mongodb \
    --network rocketchat \
    --volume rocketchat-mongodb:/data/db \
    "docker.io/mongodb/mongodb-community-server:${MONGODB_VERSION}-ubi8" \
    mongod --replSet rs0 --bind_ip_all

podman exec rocketchat-mongodb \
    mongosh --quiet --eval \
    'rs.initiate({_id: "rs0", members: [{_id: 0, host: "rocketchat-mongodb:27017"}]})'

Rocket.Chat starten. MONGO_URL zeigt mit ?replicaSet=rs0 auf das Replica Set, ROOT_URL ist die öffentliche Adresse, die der Reverse Proxy bedient:

podman run \
    --detach \
    --name rocketchat \
    --network rocketchat \
    --publish 127.0.0.1:3000:3000 \
    --env "MONGO_URL=mongodb://rocketchat-mongodb:27017/rocketchat?replicaSet=rs0" \
    --env "MONGO_OPLOG_URL=mongodb://rocketchat-mongodb:27017/local?replicaSet=rs0" \
    --env "ROOT_URL=https://chat.example.com" \
    --env "PORT=3000" \
    "registry.rocket.chat/rocketchat/rocket.chat:${RC_VERSION}"

Rocket.Chat lauscht im Container auf Port 3000. Das --publish 127.0.0.1:3000:3000 bindet diesen Port nur an localhost, sodass der Dienst nicht direkt von aussen erreichbar ist, sondern ausschliesslich über den lokalen Reverse Proxy.

Update

Ein Update bedeutet, das Image-Tag zu erhöhen und den Container neu zu erzeugen. Die Daten liegen in MongoDB und im Volume, nicht im Container, und bleiben erhalten. Vor einem Major-Update die Release Notes prüfen und MongoDB gegebenenfalls vorher auf eine kompatible Version heben.

RC_VERSION='7.0.1'
podman pull "registry.rocket.chat/rocketchat/rocket.chat:${RC_VERSION}"
podman rm --force rocketchat
# danach den 'podman run'-Befehl aus der Installation mit dem neuen Tag erneut ausführen

Rocket.Chat konfigurieren

Was ist nach einer Erst-Installation einzurichten?

  • Auf dem Reverse Proxy: vHost erstellen

  • Avatar für den Rocket-Administrator und „rocket.cat“ setzen

  • Standard-Sprache deutsch/englisch setzen, je nach Zielgruppe

  • Auf Wunsch die User-Registrierung abschalten: Administration > Accounts > Registration > „Registration Form: Disabled“ und „Registration Form Secret URL“

  • Mail-Einstellungen vornehmen: Administration > Email > SMTP (meist an localhost, 25)

  • Auf Wunsch PIWIK/Matomo integrieren

  • Benutzer anlegen oder LDAP integrieren. Wichtig: Benutzer auf „Verified“ setzen, damit sie im Falle einer Abwesenheit Notifications per E-Mail erhalten.

  • Die ersten Räume einrichten, Benutzer zuteilen

Betrieb hinter Reverse Proxy

SELinux - nach einer Standard-Installation wird sich der Apache Reverse Proxy nicht auf Port 3000 verbinden können:

type=AVC msg=audit(1508497633.925:12355): avc: denied { name_connect } for pid=31373 comm="httpd" dest=3000 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:ntop_port_t:s0 tclass=tcp_socket

Deshalb:

setsebool -P httpd_can_network_connect on

Beispiel für einen Apache vHost als Reverse Proxy. Er leitet an das lokal veröffentlichte Rocket.Chat (127.0.0.1:3000) weiter:

/etc/httpd/sites-available/chat.example.com.conf
<IfModule mod_ssl.c>
  <VirtualHost *:443>
    ServerName chat.example.com

    ProxyRequests Off
    ProxyVia Off

    <Location />
         Require all granted
    </Location>

    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*)           ws://127.0.0.1:3000/$1 [P,L]
    RewriteCond %{HTTP:Upgrade} !=websocket [NC]
    RewriteRule /(.*)           http://127.0.0.1:3000/$1 [P,L]

    ProxyPassReverse / http://127.0.0.1:3000/

    <Proxy *>
        Require all granted
    </Proxy>

    SSLEngine on
    SSLOptions +StrictRequire

    SSLCertificateFile /etc/letsencrypt/live/chat.example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/chat.example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/chat.example.com/chain.pem
  </VirtualHost>
</IfModule>

Siehe auch https://docs.rocket.chat/installation/manual-installation/configuring-ssl-reverse-proxy

Backup und Restore

Der gesamte Zustand liegt in MongoDB: Chats, Konfiguration und im Standard (FileUpload_Storage_Type: GridFS) auch die hochgeladenen Dateien. Ein MongoDB-Dump sichert damit alles Wesentliche. Der Rocket.Chat-Container selbst ist zustandslos, festzuhalten sind nur die Deployment-Parameter (Image-Tags RC_VERSION und MONGODB_VERSION, ROOT_URL und die übrigen --env-Werte aus der Installation). Sind die Uploads auf AmazonS3 oder das Dateisystem umgestellt, müssen diese zusätzlich gesichert werden.

Backup (Dump der Datenbank in eine Archiv-Datei auf dem Host):

podman exec rocketchat-mongodb \
    mongodump --db rocketchat --archive \
    | gzip > "rocketchat-$(date +%F).archive.gz"

Restore. Vorher den Rocket.Chat-Container stoppen, damit keine parallelen Schreibzugriffe laufen. --drop löscht jede im Dump enthaltene Collection vor dem Import, der bestehende Bestand wird also vollständig durch den Dump ersetzt:

podman stop rocketchat
gunzip --stdout "rocketchat-2026-01-01.archive.gz" \
    | podman exec --interactive rocketchat-mongodb \
        mongorestore --archive --nsInclude='rocketchat.*' --drop
podman start rocketchat

Daten-Export

Channels (Rooms) und Groups lassen sich mit https://github.com/frdmn/rocketchat-export-channel-messages als CSV oder JSON exportieren, sofern der Benutzer, den man dafür verwendet, die Zugriffsrechte auf die Ressourcen hat. Der Raum-Name muss bekannt sein, also vorher mit dem API-Call channels.list etc. arbeiten.

Posten von Messages per Skript

Dafür gibt es zwei Möglichkeiten:

  1. Man postet unter einem bestimmten Benutzer und legt in der Weboberfläche im Profil unter „My Account > Personal Access Tokens“ ein Token an. Das erhaltene Token und die User ID verwendet man dann beispielsweise mit curl:

    curl --header 'X-Auth-Token: YOUR-ACCESS-TOKEN' \
        --header 'X-User-Id: YOUR-USER-ID' \
        --header 'Content-type: application/json' \
        --data '{ "channel": "CHANNEL-NAME", "text": "Test message" }' \
        https://chat.example.com/api/v1/chat.postMessage
    
  2. Man arbeitet mit Webhooks (bevorzugt). Solch einen Hook erstellt man unter „Administration > Integrations > New Integration“, zum Beispiel für einen Raum oder einen Benutzer. Auf der Admin-Seite ist beschrieben, wie man weiter vorgeht. Nicht vergessen, den Absender der Nachricht zum Channel hinzuzufügen, z.B. den Benutzer „rocket.cat“:

    curl --request POST \
        --header 'Content-Type: application/json' \
        --data '{ "channel": "CHANNEL-NAME", "text": "Test message" }' \
        https://chat.example.com/hooks/T6yRim2606JJjfNSRKLqya0815a9QygBvsepZ9wQT
    

Push-Nachrichten

Oft gefragt: Muss ich meine Instanz bei Rocket.Chat registrieren? Wird eine Push-Nachricht nicht von meinem Server direkt verschickt?

Die Push-Notifications können nicht direkt vom eigenen Rocket.Chat-Server versendet werden: die App-Stores von Google und Apple verlangen, dass in der kompilierten Mobile App fix hinterlegt ist, von welchem Server Push-Notifications stammen. Das Gateway ist also nicht frei konfigurierbar.

Um trotzdem Push-Notifications zu ermöglichen, hostet Rocket.Chat ein Push-Gateway, welches in den Apps hinterlegt ist. Der eigene Rocket.Chat-Server sendet seine Notifications an das Push-Gateway von Rocket.Chat, welches diese dann an das mobile Endgerät weiterleitet. Stand 2020-11 sind kostenlos maximal 10’000 Push-Nachrichten pro Monat möglich. Wer mehr benötigt, löst ein Abo, oder man erhält bei Erreichen des Kontingents bis zum Monatsende keine Notifications mehr. Eine Registrierung ist inzwischen damit Pflicht. Siehe auch https://forums.rocket.chat/t/enforcing-registration-requirement-to-utilize-push-gateway/7545

Das offizielle Push-Gateway ist über https://gateway.rocket.chat auf Port 443 erreichbar. Das Senden einer Push-Nachricht vom Rocket.Chat-Server aus ist so auch über einen Outbound-Proxy-Server möglich.

Alternativ kann man ein eigenes Push-Gateway betreiben - allerdings muss man dann die Mobile Apps selbst kompilieren und in den App-Stores anbieten. Davon ist daher abzuraten. Siehe auch https://github.com/RocketChat/Rocket.Chat/issues/8692 und https://forums.rocket.chat/t/your-own-push-notifications-not-using-the-default-gateway/7063/2.

Wer Angst hat, dass die Push-Nachrichten sensitive Daten enthalten, die die Rocket.Chat-Entwickler mitlesen können, sendet seine Notifications einfach ohne Inhalt: „Administration > Settings > Push > Privacy > Show Message in Notification: off“.

API

Die Administration läuft auch über die REST-API. Die verfügbaren Methoden sind unter https://developer.rocket.chat/apidocs dokumentiert.

Am Anfang steht der Login. Man erhält einen „authToken“ und eine „userId“, die für alle nachfolgenden Requests benötigt werden.

RC_URL=chat.example.com
RC_USERNAME=linus
RC_PASSWORD=linuxfabrik

curl \
    --request POST \
    --silent \
    --header 'accept: application/json' \
    --header 'content-type: application/json' \
    --data "{\"user\":\"$RC_USERNAME\",\"password\":\"$RC_PASSWORD\"}" \
    "https://$RC_URL/api/v1/login" | jq --raw-output '"X-Auth-Token: \(.data.authToken)\nX-User-Id: \(.data.userId)"'

Server-Informationen auslesen, geht ohne Anmeldung (liefert JSON, ohne Anmeldung nur die Versionsnummer):

curl https://$RC_URL/api/v1/info

Alle Einstellungen holen:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    https://$RC_URL/api/v1/settings

Tipp

Bei Problemen mit der API:

  • Der --data-Body muss gültiges JSON sein, also mit doppelten Anführungszeichen, nicht mit einfachen.

  • Ein Blick ins Server-Log hilft oft weiter (podman logs beim Container, sonst journalctl).

Infos über einen Benutzer auslesen:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    https://$RC_URL/api/v1/users.info?username=myuser

Tipp

Der count-Parameter unterstützt maximal 250 Datensätze. Der offset beginnt bei 0.

Benutzer von 250 bis 500 auflisten und mit Hilfe von jq als csv exportieren:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    https://$RC_URL/api/v1/users.list?count=250\&offset=250 | jq --raw-output '.users[] | [.username, .lastLogin] | @csv' > login.csv

Benutzer von 250 bis 500 darauf prüfen, ob sie online sind (filtern mittels jq):

curl \
    --silent \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    https://$RC_URL/api/v1/users.list?count=250\&offset=250 | jq --raw-output '.users[] | select(.status == "online") | .username'

Benutzer von 250 bis 500 auflisten, die eine nicht-verifizierte E-Mail-Adresse haben (filtern mittels jq):

curl \
    --silent \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    https://$RC_URL/api/v1/users.list?count=250\&offset=250 | jq --raw-output '.users[] | select(.emails[0].verified == false) | .username'

Einen Benutzer deaktivieren (die hier beispielhaft angegebene User-UUID vorher per /api/v1/users.list ermitteln):

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    --data '{ "userId": "0d68d4ce-2b4e-4e3b-ba89-bfa68517668f", "activeStatus": false }' \
    https://$RC_URL/api/v1/users.setActiveStatus

Alle User der Gruppe „$role“ deaktivieren, welche in den letzten 365 Tagen inaktiv waren:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    --data "{ \"daysIdle\": 365, \"role\": \"$role\" }" \
    https://$RC_URL/api/v1/users.deactivateIdle

Alle Channels des Benutzers auflisten, der sich hier mit seinem Token einloggt (es werden also nur Channels aufgelistet, bei denen der Benutzer auch Mitglied ist):

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    https://$RC_URL/api/v1/channels.list

Alle Rooms abrufen:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    "https://$RC_URL/api/v1/rooms.adminRooms?count=100"

Infos über einen Channel auslesen:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    https://$RC_URL/api/v1/channels.info?roomName=myroom

Notification-Einstellungen für alle Channels anpassen:

for room_id in $(curl --header "X-User-Id: $USER_ID" --header "X-Auth-Token: $AUTH_TOKEN" --header "Content-type: application/json"  https://$RC_URL/api/v1/rooms.get | jq '.update[] | select(.t == "p")._id'); do
    curl \
        --header "X-User-Id: $USER_ID" \
        --header "X-Auth-Token: $AUTH_TOKEN" \
        --header "Content-type: application/json" \
        --data-raw "{ \
            \"roomId\": $room_id, \
            \"notifications\": {
                \"disableNotifications\": \"0\", \
                \"muteGroupMentions\": \"0\", \
                \"hideUnreadStatus\": \"0\", \
                \"hideMentionStatus\": \"0\", \
                \"desktopNotifications\": \"default\", \
                \"audioNotificationValue\": \"default\", \
                \"mobilePushNotifications\": \"default\", \
                \"emailNotifications\": \"default\" \
            } \
        }" \
        https://$RC_URL/api/v1/rooms.saveNotification
done

User als Owner für alle Gruppen setzen:

new_owner_user_id=...
for room_id in $(curl --header "X-User-Id: $USER_ID" --header "X-Auth-Token: $AUTH_TOKEN" --header "Content-type: application/json"  https://$RC_URL/api/v1/groups.listAll\?count\=100 | jq '.groups[] | select(.t == "p")._id'); do
    echo "Room ID: $room_id"
    curl \
        --header "X-User-Id: $USER_ID" \
        --header "X-Auth-Token: $AUTH_TOKEN" \
        --header "Content-type: application/json" \
        --data "{ \"roomId\": $room_id, \"userId\": \"$new_owner_user_id\" }" \
        https://$RC_URL/api/v1/groups.addOwner
done

Liste aller Gruppen mit einem bestimmten Teilnehmer:

search_user=linus
for room_name in $(curl --header "X-User-Id: $USER_ID" --header "X-Auth-Token: $AUTH_TOKEN" --header "Content-type: application/json"  https://$RC_URL/api/v1/groups.listAll\?count\=100 | jq '.groups[] | select(.t == "p").name' --raw-output); do
    if curl \
        --header "X-User-Id: $USER_ID" \
        --header "X-Auth-Token: $AUTH_TOKEN" \
        --header "Content-type: application/json" \
        "https://$RC_URL/api/v1/groups.members?roomName=$room_name" --silent | grep "$search_user" > /dev/null; then
        echo "User is in: $room_name"
    fi
done

Channel löschen:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    --data '{ "roomName": "myroom" }' \
    https://$RC_URL/api/v1/channels.delete

Alle Private Groups auflisten:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    https://$RC_URL/api/v1/groups.listAll

Private Group löschen - das geht nur, wenn der API-User auch Admin-Mitglied der Private Group ist:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    --data '{ "roomName": "myroom" }' \
    https://$RC_URL/api/v1/groups.delete

Einen Member aus einem Channel entfernen:

curl \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    --data '{ "roomName": "myroom", "username": "userName" }' \
    https://$RC_URL/api/v1/channels.kick

Script um einen User zu allen privaten Channels hinzuzufügen:

#!/usr/bin/env bash

RC_URL="chat.example.com"
RC_USERNAME="linus"
RC_PASSWORD="linuxfabrik"

if [[ -z "$RC_URL" || -z "$RC_USERNAME" || -z "$RC_PASSWORD" ]]; then
    echo "Error: Please set RC_URL, RC_USERNAME, and RC_PASSWORD environment variables."
    exit 1
fi


echo "Authenticating user..."
AUTH_RESPONSE=$(curl \
    --request POST \
    --silent \
    --header 'accept: application/json' \
    --header 'content-type: application/json' \
    --data "{\"user\":\"$RC_USERNAME\",\"password\":\"$RC_PASSWORD\"}" \
    "https://$RC_URL/api/v1/login")
AUTH_TOKEN=$(jq --raw-output '.data.authToken // empty' <<< "$AUTH_RESPONSE")
USER_ID=$(jq --raw-output '.data.userId // empty' <<< "$AUTH_RESPONSE")

if [[ -z "$AUTH_TOKEN" || -z "$USER_ID" ]]; then
    echo "Error: Authentication failed. Check credentials or URL."
    echo "Response: $AUTH_RESPONSE"
    exit 1
fi
echo "Authentication successful."

echo "Fetching private rooms list..."
ROOMS_JSON=$(curl \
    --silent \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    "https://$RC_URL/api/v1/rooms.adminRooms?types[]=p&count=10000")
readarray -t room_ids < <(jq --raw-output ".rooms[]? | ._id // empty" <<< "$ROOMS_JSON")

if (( ${#room_ids[@]} == 0 )); then
    echo "No private rooms found."
    exit 0
fi
echo "Found ${#room_ids[@]} private rooms. Attempting to add user ID '$USER_ID'..."

for room_id in "${room_ids[@]}"; do
    echo " - Inviting user to Room ID: $room_id"
    INVITE_RESPONSE=$(curl \
        --request POST \
        --silent \
        --header "X-Auth-Token: $AUTH_TOKEN" \
        --header "X-User-Id: $USER_ID" \
        --header 'Content-type: application/json' \
        --data "{\"roomId\": \"$room_id\", \"userId\": \"$USER_ID\"}" \
        "https://$RC_URL/api/v1/groups.invite")

    if jq --exit-status '.success == true' > /dev/null <<< "$INVITE_RESPONSE"; then
        echo "   ... Success."
    else
        echo "   ... Failed."
    fi
    sleep 0.2
done

Das Gegenteil, einen User aus allen Channels entfernen:

#!/usr/bin/env bash

RC_URL="chat.example.com"
RC_USERNAME="linus"
RC_PASSWORD="linuxfabrik"

if [[ -z "$RC_URL" || -z "$RC_USERNAME" || -z "$RC_PASSWORD" ]]; then
    echo "Error: Please set RC_URL, RC_USERNAME, and RC_PASSWORD environment variables."
    exit 1
fi

echo "Authenticating user..."
AUTH_RESPONSE=$(curl \
    --request POST \
    --silent \
    --header 'accept: application/json' \
    --header 'content-type: application/json' \
    --data "{\"user\":\"$RC_USERNAME\",\"password\":\"$RC_PASSWORD\"}" \
    "https://$RC_URL/api/v1/login")

AUTH_TOKEN=$(jq --raw-output '.data.authToken // empty' <<< "$AUTH_RESPONSE")
USER_ID=$(jq --raw-output '.data.userId // empty' <<< "$AUTH_RESPONSE")
if [[ -z "$AUTH_TOKEN" || -z "$USER_ID" ]]; then
    echo "Error: Authentication failed. Check credentials or URL."
    echo "Response: $AUTH_RESPONSE"
    exit 1
fi
echo "Authentication successful."

# username of the user to remove from all private groups
USER_TO_REMOVE="someuser"
USERID_TO_REMOVE=$(curl \
    --silent \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    "https://$RC_URL/api/v1/users.info?username=$USER_TO_REMOVE" | \
    jq --raw-output '.user._id')

echo "Fetching private rooms list..."
ROOMS_JSON=$(curl \
    --silent \
    --header "X-Auth-Token: $AUTH_TOKEN" \
    --header "X-User-Id: $USER_ID" \
    --header "Content-type: application/json" \
    "https://$RC_URL/api/v1/rooms.adminRooms?types[]=p&count=10000")

readarray -t room_ids < <(jq --raw-output ".rooms[]? | ._id // empty" <<< "$ROOMS_JSON")
if (( ${#room_ids[@]} == 0 )); then
    echo "No private rooms found."
    exit 0
fi
echo "Found ${#room_ids[@]} private rooms. Attempting to remove user ID '$USERID_TO_REMOVE'..."

for room_id in "${room_ids[@]}"; do
    echo " - Removing user from Room ID: $room_id"
    RESPONSE=$(curl \
        --request POST \
        --silent \
        --header "X-Auth-Token: $AUTH_TOKEN" \
        --header "X-User-Id: $USER_ID" \
        --header 'Content-type: application/json' \
        --data "{\"roomId\":\"$room_id\",\"userId\":\"$USERID_TO_REMOVE\"}" \
        "https://$RC_URL/api/v1/groups.kick")

    if jq --exit-status '.success == true' > /dev/null <<< "$RESPONSE"; then
        echo "   ... Success."
    else
        echo "   ... Failed."
    fi
    sleep 0.2
done

Migration von Server A nach Server B

Sicherstellen, dass auf Server A und B die gleiche Rocket.Chat-Version installiert ist.

Auf Host A den Dienst stoppen, die Datenbank dumpen und das Archiv auf Host B kopieren:

systemctl stop rocketchat
mongodump --db rocketchat --out /tmp/mongodump/
tar --create --gzip --file /tmp/mongodump.tar.gz --directory /tmp/mongodump .
scp /tmp/mongodump.tar.gz hostb:/tmp/

Auf Host B den Dienst stoppen, das Archiv auspacken und den Dump einspielen. --drop löscht jede im Dump enthaltene Collection vor dem Import, der bestehende Bestand wird also vollständig durch den Dump ersetzt. Die ältere --db-Option von mongorestore ist seit MongoDB 4.4 veraltet, die Ziel-Datenbank wird stattdessen über --nsInclude gewählt:

systemctl stop rocketchat
tar --extract --gzip --file /tmp/mongodump.tar.gz --directory /tmp/mongodump
mongorestore /tmp/mongodump/rocketchat --nsInclude='rocketchat.*' --drop
systemctl start rocketchat

Client

Auf Fedora wird der Flatpak-Client von Flathub bevorzugt. Er aktualisiert sich automatisch über den Flatpak-Update-Mechanismus und bleibt damit auf einer aktuellen Version. Das einzelne RPM von der GitHub-Releases-Seite wird hingegen nicht über dnf aktualisiert und veraltet entsprechend schnell. Symptom eines zu alten Desktop-Clients gegenüber einem aktuellen Server: einzelne Channels rendern mit Oops! Something went wrong, während derselbe Channel im Browser-Client weiterhin funktioniert.

sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install flathub chat.rocket.RocketChat

Falls bereits ein RPM-Client installiert ist, vorher entfernen (inklusive lokaler Cache- und Login-Daten unter ~/.config/Rocket.Chat):

sudo dnf remove rocketchat
rm -rf ~/.config/Rocket.Chat

Alternative über das einzelne RPM von der Releases-Seite (manuelle Updates erforderlich):

VER=4.14.1
dnf --assumeyes install https://github.com/RocketChat/Rocket.Chat.Electron/releases/download/$VER/rocketchat-$VER-linux-x86_64.rpm

Suchen

Eine Übersicht aller Suchoperatoren:

Personen-Filter

Operator

Beschreibung

from:username

Nachrichten von einem bestimmten User

from:me

Eigene Nachrichten

mention:username

Nachrichten die einen User erwähnen

Nachrichten-Status

Operator

Beschreibung

has:star

Nachrichten die du mit Stern markiert hast

is:pinned / has:pin

Angepinnte Nachrichten

has:url / has:link

Nachrichten mit Links

has:location / has:map

Nachrichten mit Standort

Dateien & Anhänge

Operator

Beschreibung

label:name

Nach Attachment-Label filtern (z.B. label:“review needed“)

file-title:titel

Nach Dateititel filtern

file-desc:beschreibung

Nach Dateibeschreibung filtern

Datum

Format: DD/MM/YYYY, DD.MM.YYYY oder DD-MM-YYYY

Operator

Beschreibung

before:01-01-2023

Nachrichten vor einem Datum

after:01-01-2023

Nachrichten nach einem Datum

on:01-01-2023

Nachrichten an einem bestimmten Tag

Sortierung

Operator

Beschreibung

order:asc / sort:asc

Älteste zuerst

order:desc / sort:desc

Neueste zuerst (Standard)

Freitext
  • Normaler Text wird per MongoDB-Textsuche gesucht

  • Regex möglich: /^text$/i

  • Operatoren sind kombinierbar: from:me after:01-01-2026 has:link suchbegriff

Admin-Einstellungen
  • Message_AlwaysSearchRegExp - erzwingt Regex statt Textsuche

  • GlobalSearchEnabled — Suche über alle zugänglichen Räume hinweg (standardmässig aus)

Troubleshooting

Den einzigen Admin eines Raumes entfernt?

Schlecht, denn dann lässt sich der Raum auch vom globalen Admin-Account nicht mehr über die Rocket.Chat-Oberfläche administrieren.

Lösung: ausgewählte User per API einem Raum zuordnen, (einen) User zum Admin und Raum-Owner machen, Raum administrieren/löschen, unnötige Benutzer entfernen und zu hoch vergebene Rechte wieder entfernen.

File-Uploads funktionieren nicht?

In /var/log/messages taucht folgendes auf?

rocket-chat: ufs: cannot write chunk of file "YJQb5H6y7YaE9psAM" (ENOENT: no such file or directory, open '/tmp/ufs/YJQb5H6y7YaE9psAM')
rocket-chat: ufs: cannot delete temp file "/tmp/ufs/YJQb5H6y7YaE9psAM" (ENOENT: no such file or directory, unlink '/tmp/ufs/YJQb5H6y7YaE9psAM')
rocket-chat: [Error: FileNotFound: no file with id YJQb5H6y7YaE9psAM found]

Lösung:

mkdir /tmp/ufs
chown rocketchat:rocketchat /tmp/ufs
Login der Smartphone-App funktioniert auch nach Neuinstallation der App nicht?

2FA deaktivieren, Login, 2FA aktivieren