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 bringt die Enterprise-Variante?

  • Infrastructure: High Scalability

  • Administration: Feature 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

Links

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 im Grunde eine Sammlung von Channels, die jeweils einem bestimmten Zweck, Kunden oder Projekt dienen. Ein Team enthält ausgewählte Mitglieder einer Organisation und eine Reihe von Channels, die auf die Rollen dieser Mitglieder zugeschnitten sind. Der Hauptvorteil liegt in der Automatisierung der Zugriffsrechte: Wenn ein neues Mitglied dem Team beitritt, erhält es sofort Zugang zu allen zugehörigen Channels, sofern im Team der Haken „Auto-join“ beim jeweiligen Channel in der Channel-Liste aktiviert ist. Dadurch müssen Mitglieder nicht mehr manuell zu jedem Kanal hinzugefügt werden, was die Effizienz steigert und den Verwaltungsaufwand reduziert.

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 teilehmen 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.

Update

Ein Update/Upgrade entspricht dem Vorgehen der Neuinstallation:

Shutdown Rocket.Chat
Goto the installation folder: cd /opt/
Remove or move the Rocket.Chat folder.
Follow the installation section

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, der als Reverse Proxy agiert:

<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://10.80.32.19:3000/$1 [P,L]
    RewriteCond %{HTTP:Upgrade} !=websocket [NC]
    RewriteRule /(.*)           http://10.80.32.19:3000/$1 [P,L]

    ProxyPassReverse / http://10.80.32.19: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

Backup:

  • /opt sichern

  • Mongo-Dump sichern

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 channel.listAll 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-Page ist dann auch alles beschrieben, man weiter vorgehen muss. 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-Notifcations 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 pro 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. Ein eigenes Push-Gateway empfehlen wir daher nicht. 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 klappt auch per API. Das API findet sich dokumentiert auf https://github.com/RocketChat/developer-docs/tree/master/reference/api/rest-api und im Source Code unter packages/rocketchat-api/server/v1.

Welche API-Methoden sind verfügbar (die Doku hinkt für gewöhnlich hinterher)?

git clone https://github.com/RocketChat/Rocket.Chat
grep -ir 'API\.v1\.addRoute' Rocket.Chat

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.linuxfabrik.io
RC_USERNAME=linus
RC_PASSWORD=linuxfabrik

AUTH_RESPONSE=$(curl \
    --silent \
    --data "user=$RC_USERNAME&password=$RC_PASSWORD" \
    https://$RC_URL/api/v1/login)
AUTH_TOKEN=$(echo $AUTH_RESPONSE | jq -r '.data.authToken')
USER_ID=$(echo $AUTH_RESPONSE | jq -r '.data.userId')

Info über Rocket.Chat auslesen - geht ohne Login (und es kommt HTML zurück):

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

Probleme mit dem API?

  • Das API mag keine Single-Quotes innerhalb des --data JSON-Dictionary.

  • Eventuell hilft ein Blick in /var/log/messages.

Benutzern in einem Raum eine Nachricht senden (hier per Webhook):

curl \
    --header "Content-Type: application/json" \
    --data '{ "text": ":hammer_pick: Was habt ihr für heute geplant? :hammer_pick:" }'
    https://$RC_URL/hooks/89b730ea-5dad-4f15-84cb-9999119cba91

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 -r '.users[] | [.username, .lastLogin] | @csv' > login.csv

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

curl \
    --silent \
    --head \
    --header "X-User-Id: $USER_ID \
    https://$RC_URL/api/v1/users.list?count=250\&offset=250 | jq -r '.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 -r '.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 auflisten (Rooms):

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

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 \
    --request DELETE \
    --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

Migration von Server A nach Server B

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

# Host A
systemctl stop rocketchat
mongodump --db rocketchat --out /tmp/mongodump/
tar cvf backup.tar ~/backup
scp backup.tar hostb:...

# Host B
systemctl stop rocketchat
# deprecated synatx
# mongorestore /tmp/mongodump/rocketchat --db rocketchat --drop
mongorestore /tmp/mongodump/rocketchat --nsInclude='rocketchat.*' --drop
systemctl start rocketchat

Achtung! --drop löscht alle Tablellen, die im Dump vorhanden sind, bevor es den Dump einfügt.

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

Client

Auf Fedora:

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

Auf Fedora funktioniert auch der Flatpak-basierte Client (hatte bei mir allerdings ein paar Stabilitätsprobleme):

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

Built on 2024-09-30