Rocket.Chat vs. Matrix/Synapse

Seit der Eröffnung von social.eden.one betreibe ich zwei Anwendungen im Small Web, und obwohl ich der radikalen Vision (Jeder muss sein eigener Server sein) eher skeptisch gegenüber stehe – die freien Serverkapazitäten und die schöne Domain eden.one fordern den Betrieb weiterer Anwendungen geradezu heraus. Nachdem vor einigen Monaten viel Zeit in den Serverbetrieb für eine völlig antiquierte Technologie (mit überraschendem Optimierungspotential auf mehreren Ebenen) geflossen ist, steht heute eine jüngere Kommunikationsform auf dem Programm.

Selbst Online-Chats sind älter als ich, und die noch heute verwendeten Protokolle evozieren eine weit zurückliegende Zeit vor dem Siegeszug des WWW. Damals chatteten meist Gruppen von Menschen themenbezogen in rooms oder channels, und Chats waren nur synchron möglich, wenn eine Einwahlmöglichkeit bestand. IRC-Dienste wie Libera haben im Wesentlichen noch dieses Profil. In modernen Chat-Plattformen für Unternehmen/Organisationen (Slack, Mattermost etc) treten neben die thematischen Kanäle Gruppen- oder Teamräume, und die Oberflächen haben sich seit den IRC-Hochzeiten deutlich weiterentwickelt. Gleichzeitig hat sich im privaten Bereich Instant Messaging als dominante Chat-Variante durchgesetzt. Diese Kommunikation (synchron oder asynchron) zwischen (mindestens) zwei Menschen erfolgt vor allem auf mobilen Endgeräten mit Diensten wie WhatsApp, Signal, Telegram oder Threema. Die Grenzen zwischen einem traditionellen Chat-Dienst und einem Messenger sind fließend, denn Kanäle lassen sich auch in einem Messenger einrichten – vor allem auf Telegram sind öffentliche Kanäle sehr populär.

Bei allen Unterschieden im Detail stützen sich fast alle Chat-/Messaging-Dienste auf eine Client-Server-Architektur, in der der Server nicht von den Nutzerinnen kontrolliert wird, und die Ausnahmen (Tox, Briar) richten sich laut Messenger-Matrix an Nerds. Als Nicht-Nerd bleibt mir da nur, testweise eigene Chatserver aufzusetzen, um meinen trust issues und der Abhängigkeit von fremden Admins zu entkommen.

Der erste Testkandidat ist die Slack-Alternative Rocket.Chat. Ich ziehe ausnahmsweise die Installation via Snap dem manuellen Setup vor, weil ich nicht ein weiteres RDBMS (MongoDB) und eine zusätzliche Node.js-Version verwalten möchte. Entsprechend schnell geht alles, nach der Installation müssen lediglich zwei Parameter angepasst werden (u.a. um eine Kollision mit dem Mastodon-Port zu vermeiden):

$ snap install rocketchat-server $ snap set rocketchat-server siteurl=https://chat.eden.one $ snap set rocketchat-server port=4004 $ snap get rocketchat-server Key Value backup-on-refresh disable ignore-errors false mongo-oplog-url mongodb://localhost:27017/local mongo-url mongodb://localhost:27017/parties port 4004 siteurl https://chat.eden.one

Für die neue Subdomain wird ein Zertifikat benötigt (certbot certonly --nginx -d chat.eden.one), und Nginx wird als reverse proxy eingespannt:

server { listen 443 ssl http2; server_name chat.eden.one; client_max_body_size 200M; error_log /var/log/nginx/rocketchat.access.log; ssl_certificate /etc/letsencrypt/live/chat.eden.one/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/chat.eden.one/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; location / { proxy_pass http://127.0.0.1:4004/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $http_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 https; proxy_set_header X-Nginx-Proxy true; proxy_redirect off; } }

Alle weiteren Konfigurationsschritte erfolgen über das Web-Interface der Applikation, vor allem die Erstellung eines Admin-Accounts (🫣), der Eintrag der SMTP-Zugangsdaten, die 2FA-Aktivierung und (in meinem Fall) die Beschränkung der Einrichtung neuer Konten (Admin → Accounts → Registration → Registration Form → Secret URL) sowie die Ergänzung des Templates für Einladungen um die Secret URL:

<h2>{Welcome_to Site_Name}</h2><p>{Visit_Site_Url_and_try_the_best_open_source_chat_solution_available_today}</p><a class="btn" href="[Site_URL]/register/ynUpX8gKoKwD9j9wY">{Join_Chat}</a>

Grundsätzlich kann man Rocket.Chat als standalone server betreiben, aber um Push-Benachrichtigungen an die mobilen Apps (iOS/Android) zu versenden (kostenfrei bis zu 10.000 pro Monat), muss der Server registriert werden (entgegen der Prämisse des Tests).

Nach einem Neustart des Service (systemctl restart snap.rocketchat-server.rocketchat-server.service) funktioniert alles einwandfrei (TTL < 20m). Der Komfort hat natürlich seinen Preis: Innerhalb von 24 Stunden werde ich zweimal 48 Stunden werde ich viermal vom Rocket.Chat-Vertrieb kontaktiert, basierend auf der Registrierung für die Rocket.Chat Cloud (und der heimtückischen Einstellung Allow Marketing Emails). Der Fokus auf (zahlungsbereite) Unternehmen und auf die interne Kommunikation dieser Unternehmen ist sehr eindeutig. Rocket.Chat unterscheidet zwischen Channels, Teams, Direct Messages und Discussions, was für eine differenzierte unternehmensweite Kommunikation hilfreich, für soziale Kommunikation aber weniger relevant ist.

Ein föderierter Einsatz mit anderen Servern steht ebenfalls nicht im Vordergrund (Federation Support is a work in progress. Use on a production system is not recommended at this time.), obwohl sich Rocket.Chat sogar mit der Matrix verbinden ließe (wenn man ihm einen eigenen Matrix-Homeserver zur Verfügung stellte). E2E-Verschlüsselung gegen maliziöse Admins (This feature is currently in beta!) ist keine Stärke des Systems; nur unter bestimmten Bedingungen können zwei Personen mit Rocket.Chat vertraulich kommunizieren. Aktuell gehöre ich deshalb nicht zur Rocket.Chat-Zielgruppe (sorry, Aditya!).

Die Referenzimplementierung der Matrix-Spezifikation, Synapse, ist in vielerlei Hinsicht das Gegenteil von Rocket.Chat: E2E-Verschlüsselung und Föderation zählen zur Kernfunktionalität, dafür bietet Synapse kein Web-Interface und (mangels entsprechender Spezifikation) keine 2-Faktor-Authentifizierung via TOTP. Stattdessen wird bei der erstmaligen Anmeldung in einem Client ein Schlüssel erzeugt, den man in Form einer Security Phrase bei Anmeldungen in anderen Clients als zweiten Faktor verwenden muss (und den auch die Administratorin nicht kennt).

Die für Synapse empfohlene Installationsmethode ist ein Ansible Playbook, mit dem Synapse (und andere Anwendungen) in einem Docker-Container bereitgestellt werden – eindeutig zu viele Abstraktionsebenen für mich. Ich wähle den traditionellen Weg:

sudo apt install -y lsb-release wget apt-transport-https wget -O /usr/share/keyrings/matrix-org-archive-keyring.gpg https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] https://packages.matrix.org/debian/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/matrix-org.list sudo apt update sudo apt install matrix-synapse-py3

Im Zuge der Installation werde ich nach dem gewünschten server_name gefragt, dessen Unabänderlichkeit und Bedeutung in den ersten Sätzen der Dokumentation unmissverständlich erklärt wird:

It is important to choose the name for your server before you install Synapse, because it cannot be changed later.

The server name determines the "domain" part of user-ids for users on your server: these will all be of the format @user:my.domain.name. It also determines how other matrix servers will reach yours for federation.

For a test configuration, set this to the hostname of your server. For a more production-ready setup, you will probably want to specify your domain (example.com) rather than a matrix-specific hostname here (in the same way that your email address is probably user@example.com rather than user@email.example.com) - but doing so may require more advanced setup: see Setting up Federation.

Natürlich überlese ich diesen eindringlichen Hinweis und wähle den Servernamen matrix.eden.one, zunächst ohne nachteilige Effekte. Wie üblich benötigt Synapse ein Zertifikat (certbot certonly --nginx -d matrix.eden.one) und einen reverse proxy:

server { listen 443 ssl http2; listen [::]:443 ssl http2; # For the federation port listen 8448 ssl http2 default_server; listen [::]:8448 ssl http2 default_server; server_name matrix.eden.one; ssl_certificate /etc/letsencrypt/live/matrix.eden.one/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/matrix.eden.one/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; location ~ ^(/_matrix|/_synapse/client) { proxy_pass http://localhost:8008; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; client_max_body_size 50M; } }

Etwas widerwillig öffne ich Port 8448 in der Firewall, damit mein frisch gestarteter Homeserver (systemctl start matrix-synapse.service) mit anderen Matrix-Servern sprechen kann, und melde mich stolz im Chatraum des Göttinger CCC (#neotopia:matrix.cccgoe.de). Dort werde ich angesichts meines Namens @janedenone:matrix.eden.one freundlich darauf hingewiesen, dass Delegation offenbar nicht richtig konfiguriert wurde (was mich zum vorschnell gewählten server_name zurückführt).

Obwohl die Umbenennung eines Homeservers kein neues Anliegen ist, wird der Wunsch nach einem anderen server_name in den FAQs als einer der wenigen Anwendungsfälle für tabula rasa genannt:

Deleting your database is unlikely to make anything better.

It's easy to make the mistake of thinking that you can start again from a clean slate by dropping your database, but things don't work like that in a federated network: lots of other servers have information about your server.

For example: other servers might think that you are in a room, your server will think that you are not, and you'll probably be unable to interact with that room in a sensible way ever again.

In general, there are better solutions to any problem than dropping the database. Come and seek help in https://matrix.to/#/#synapse:matrix.org.

There are two exceptions when it might be sensible to delete your database and start again:

Nach Rücksprache mit den netten Menschen in #synapse:matrix.org

Nginx ist jetzt so konfiguriert –

# /etc/nginx/sites-enabled/default location /.well-known/matrix/client { return 200 '{"m.homeserver": {"base_url": "https://matrix.eden.one"}}'; default_type application/json; add_header Access-Control-Allow-Origin *; } location /.well-known/matrix/server { return 200 '{"m.server": "matrix.eden.one:443"}'; # explicit port required, default is 8448 default_type application/json; add_header Access-Control-Allow-Origin *; } # /etc/nginx/sites-enabled/matrix server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name matrix.eden.one; ssl_certificate /etc/letsencrypt/live/matrix.eden.one/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/matrix.eden.one/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; location / { proxy_pass http://localhost:8008; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; client_max_body_size 50M; } }

– dass der Aufruf von matrix.eden.one ein unmittelbares Erfolgserlebnis generiert –

matrix

It works! Synapse is running

Your Synapse server is listening on this port and is ready for messages.

To use this server you'll need a Matrix client.

Welcome to the Matrix universe :)

– und ich mit Hilfe der Client Well-Known URI Adressen der Form @matrixuser:eden.one verwenden kann. Dank der Synapse-Dokumentation war der Weg zu diesem Ziel etwas verschlungener als nötig: Obwohl die Installationsanleitung eine Nginx-Konfiguration für .well-known/matrix/client enthält, fehlt das Pendant für die Server-Delegation auf der reverse proxy-Seite (sie enthält nur Beispiele für Caddy und HAProxy). Mit der obigen Konfiguration ist der Federation Tester jedenfalls zufrieden.

Zum Abschluss konfiguriere ich den E-Mail-Versand (und stolpere wie üblich ein wenig über die SSL/TLS-Einstellungen). Damit sich Links in E-Mails auf matrix.eden.one (und nicht auf den server_name eden.one) beziehen, muss die passende public_base_url in /etc/matrix-synapse/homeserver.yaml eingetragen werden.

Neben Synapse benötigt man einen Matrix-Client, und es wird dringend vom Betrieb von Element (und implizit anderer Clients) unter der Homeserver-Domain abgeraten:

We do not recommend running Element from the same domain name as your Matrix homeserver. The reason is the risk of XSS (cross-site-scripting) vulnerabilities that could occur if someone caused Element to load and render malicious user generated content from a Matrix API which then had trusted access to Element (or other apps) due to sharing the same domain.

Nach meiner Erfahrung mit dem leichtfertig gewählten server_name bin ich vorsichtig geworden und verwende Element in der gehosteten Web-Version, der darauf basierenden Mac-Version und iOS-Version. Obwohl der Source-Code für Element unter einer Apache 2.0-Lizenz verfügbar ist, liegt der Schwerpunkt der Monetarisierung auf kostenpflichtigen Client-Varianten (Element One verbindet die Nutzung von Matrix, Signal, WhatsApp und Telegram innerhalb einer App für $5/Monat, Stand November 2022) und nicht auf dem SaaS-Chatserver (der Vertrieb hält sich angenehm zurück). Die Alternativen zum Element-Client sind ebenfalls Open Source-Projekte, und die Installation der CLI-basierten Clients scheitert bedauerlicherweise an der verwaisten Bibliothek python-olm.

In Verbindung mit einem Matrix-Homeserver kommen häufig ein oder zwei fremde Server zum Einsatz: Der Notary Server (default: matrix.org) stellt öffentliche Schlüssel von Matrix-Servern bereit, wenn diese Server vorübergehend nicht erreichbar sind, der Identity Server (default: vector.im) ermöglicht die Suche nach Matrix-Nutzerinnen per E-Mail-Adresse (oder Telefonnummer). Die optionale Verknüpfung von E-Mail-Adressen mit Matrix-Accounts erfordert zwei Schritte:

  1. Die E-Mail-Adresse wird in einem Matrix-Client eingetragen – der Homeserver versendet eine Verifikationsmail (mit Link auf matrix.eden.one).
  2. Die E-Mail-Adresse wird für die Suche via Identity Server freigegeben – der Betreiber Element.io versendet eine Verifikationsmail (mit Link auf vector.im).

Wenn man vor der Freigabe einer (verifizierten) E-Mail-Adresse eine Nutzerin über diese Adresse zu einem Chat einlädt, verschickt Element eine E-Mail (mit Link auf app.element.io). Hat man die Adresse freigegeben, wird die Einladung über den Homeserver (mit Link auf matrix.eden.one) zugestellt und erscheint parallel im jeweils verwendeten Client. Das ist sicher technisch und rechtlich sinnvoll gestaltet, aber etwas verwirrend, zumal alle E-Mails den Namen der auslösenden Client-Anwendung (Element) in der Betreffzeile enthalten:

# Vor der Freigabe From: Element <noreply@element.io> To: matrixuser@eden.one Subject: Jan Eden has invited you to a room on Element Hi, Jan Eden (@jan:eden.one) has invited you into a room on Element. To join the conversation please follow the link below. https://app.element.io/... # Nach der Freigabe From: Your Friendly Element homeserver <matrixserver@eden.one> To: matrixuser@eden.one Subject: [Element] @jan:eden.one has invited you to chat on Element... Hi matrix, [Element] @jan:eden.one has invited you to chat on Element...Empty Room You've been invited, join at https://matrix.eden.one/...

Außerdem werden diese Einladungen (und Benachrichtigungen über neue, ungelesene Nachrichten) nur zugestellt, wenn die Nutzerin über einen Web- oder Desktop-Client angemeldet ist und dort die entsprechende Option aktiviert. Verwendet man die mobilen Element-Clients, gibt es nur Push-Benachrichtigungen. Und schließlich werden direct messages, die man über eine E-Mail-Adresse initiiert, zunächst nicht verschlüsselt (auch wenn man die Verschlüsselung nachträglich aktivieren kann), obwohl Einladungen per E-Mail in einen bereits verschlüsselten Raum möglich sind. Insgesamt spricht einiges dafür, Matrix-Kommunikation nicht auf E-Mail-Adressen zu stützen.

Element wird als Instant Messenger kategorisiert, obgleich die Matrix-Spezifikation sich ausschließlich auf öffentliche oder private Räume bezieht, von denen es mittlerweile 10 Versionen mit unterschiedlichem Funktionsumfang gibt. Der Client unterscheidet zwischen

Direct messages (chats) mit einzelnen Menschen lassen sich in der Element-Oberfläche (etwas) einfacher einrichten als rooms, und es gibt Befehle für die Umwandlung von direct messages in rooms und umgekehrt (/converttodm, /convertoroom). Technisch sind direct messages aber ebenfalls rooms, so dass an direct messages auch mehr als zwei Personen teilnehmen können (entgegen der Darstellung im Benutzerhandbuch). Um das Gesamtbild abzurunden, kann man direct messages und rooms in spaces gruppieren, wobei spaces technisch ebenfalls rooms sind. Obwohl diese Beschreibung wie der Fiebertraum einer UX-Designerin klingt, ist das Nebeneinander öffentlicher Chaträume (wie #synapse:matrix.org) und privater Kommunikation (mit @matrixuser:eden.one) gut gelöst und erleichtert die Kombination der beiden Chat-Nutzungsformen. Wenn man den ausbaufähigen Umgang mit E-Mail-Adressen (und das überschaubare Angebot an CLI-Clients) außer Acht lässt, ist ein Matrix-Homeserver eine ideale Lösung für Menschen, die verschlüsselt mit ihrem technikaffinen Bekanntenkreis kommunizieren und sich in Chaträumen weltweit austauschen möchten, ohne sich einer grenzenlosen Paranoia hinzugeben oder den Informationsaustausch ephemeral, low-stakes, and image-heavy zu gestalten.

Die Serverlast hält sich übrigens nach wie vor in Grenzen (~ 1,5% CPU, ~ 10% RAM), was an meinem sparsamen Kommunikationsverhalten liegen mag. Den Aufenthalt in belebten öffentlichen Chaträumen und einen großen Bekanntenkreis kann ich mir angesichts des Speicherhungers der Synapse-Datenbank nämlich nicht leisten.