Zum Hauptinhalt springen
  1. Posts/

Cactus Comments – Blogkommentare über den eigenen Matrix-Server

1120 Wörter·6 min· loading ·
Sebastian Zehner
Autor
Sebastian Zehner
Ursprünglich aus 🇩🇪, jetzt in 🇵🇾. Lebt im Terminal, hostet alles selbst mit Docker und baut KI-Workflows im eigenen Techlab.
Inhaltsverzeichnis

Kommentarsysteme wie Disqus sind praktisch – aber sie laden Tracking, Werbung und externe Abhängigkeiten mit. Cactus Comments macht das anders: Kommentare landen direkt in Matrix-Räumen auf dem eigenen Homeserver.

Im letzten Artikel habe ich gezeigt, wie man Synapse mit Docker aufsetzt und einen eigenen Matrix-Homeserver betreibt. Heute bauen wir darauf auf: Mit Cactus Comments bekommt jeder Blogartikel seinen eigenen Matrix-Chatraum – Leser können Kommentare hinterlassen, ohne sich bei einem Drittanbieter registrieren zu müssen, und ich habe die volle Kontrolle über meine Daten.

Was ist Cactus Comments?
#

Cactus Comments ist ein föderiertes Kommentarsystem für das offene Web, das das Matrix-Protokoll als Backend nutzt. Das Prinzip ist elegant: Für jeden Blogartikel wird automatisch ein Matrix-Raum angelegt. Wer einen Kommentar schreiben möchte, meldet sich mit seinem Matrix-Account an – das kann ein Account auf matrix.org, meinem eigenen Server oder jedem anderen Matrix-Homeserver sein. Federation sei Dank.

Das System besteht aus zwei Teilen:

  • Cactus Appservice – ein Python-Dienst, der als Matrix-Bot (hier: @cactusbot) auf dem Homeserver läuft und die Räume verwaltet
  • Cactus Client – eine JavaScript/Elm-Webanwendung, die auf dem Blog eingebettet wird und das Kommentarfeld rendert

Voraussetzungen
#

Den Cactus Client bauen
#

Der Cactus Client wird nicht als fertige Bundle-Datei ausgeliefert – er muss selbst gebaut werden. Ich möchte außerdem eine eigene Kopie im lokalen Forgejo behalten, statt mich auf GitLab zu verlassen.

Repository klonen und auf Forgejo spiegeln:

git clone https://gitlab.com/cactus-comments/cactus-client.git
cd cactus-client

git remote rename origin gitlab
git remote add origin https://git.techlab.icu/sebastianzehner/cactus-client.git

git push origin --all
git push origin --tags

Build ausführen:

npm install
npm run build

Wenn du noch kein eigenes Forgejo hast, kannst du das Spiegeln überspringen.

Möglicher Fehler: Korruptes Elm-Paket
#

Beim ersten Build-Versuch ist bei mir folgender Fehler aufgetaucht:

🚨  CORRUPT PACKAGE DATA
I downloaded the source code for ryannhg/date-format 2.3.0 from:
    https://github.com/ryannhg/date-format/zipball/2.3.0/
But it looks like the hash of the archive has changed since publication.

Das Paket ryannhg/date-format hat seit seiner Veröffentlichung einen geänderten Hash – ein bekanntes Problem bei Elm-Abhängigkeiten, wenn der Paketautor den Version-Tag nachträglich verschoben hat. Die Lösung: das Paket manuell herunterladen und an der richtigen Stelle ablegen.

cd ~/.elm/0.19.1/packages/ryannhg/date-format/2.3.0/
curl -L "https://github.com/ryannhg/date-format/zipball/2.3.0/" -o package.zip
unzip package.zip
mv ryan-haskell-date-format-b0e7928/* .
rm -rf ryan-haskell-date-format-b0e7928 package.zip

Danach nochmal bauen – diesmal erfolgreich:

✨  Built in 3.73s.

dist/cactus.js        155.95 KB
dist/style.css          6.96 KB

Den Appservice einrichten
#

Schritt 1: Tokens generieren
#

Der Appservice benötigt zwei zufällige Tokens für die Authentifizierung zwischen Synapse und Cactus:

cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 64 | head -n 2

Die erste Ausgabezeile wird as_token, die zweite hs_token. Beide gut notieren.

Schritt 2: Registration-Datei für Synapse erstellen
#

nvim ~/docker/synapse/files/cactus.yaml

Inhalt:

id: "Cactus Comments"

url: "http://cactus:5000"

as_token: "YOUR_AS_TOKEN"
hs_token: "YOUR_HS_TOKEN"

sender_localpart: "cactusbot"

namespaces:
  aliases:
    - exclusive: true
      regex: "#comments_.*"

Diese Datei teilt Synapse mit, dass es einen Appservice namens cactusbot gibt, der alle Raumaliase mit dem Präfix #comments_ verwaltet.

Schritt 3: homeserver.yaml ergänzen
#

nvim ~/docker/synapse/files/homeserver.yaml

Folgende Zeilen hinzufügen:

app_service_config_files:
  - "/data/cactus.yaml"

allow_guest_access: true
use_appservice_legacy_authorization: true
enable_authenticated_media: false

public_baseurl: "https://matrix.your-domain.com"

Wichtig: Der Pfad /data/cactus.yaml ist der Pfad innerhalb des Synapse-Containers. Bei mir ist ~/docker/synapse/files/ als /data gemountet.

Sicherheitshinweis: Die Einstellungen allow_guest_access: true, use_appservice_legacy_authorization: true und enable_authenticated_media: false sind Anforderungen des Cactus Appservice und lockern einige Sicherheitseinstellungen von Synapse. Wer das vermeiden möchte, müsste den Cactus Client entsprechend erweitern – das liegt jedoch außerhalb des Rahmens dieser Anleitung.

Schritt 4: Umgebungsvariablen für Cactus
#

nvim ~/docker-compose/synapse/cactus.env

Inhalt:

CACTUS_HS_TOKEN=YOUR_HS_TOKEN
CACTUS_AS_TOKEN=YOUR_AS_TOKEN
CACTUS_HOMESERVER_URL=http://synapse:8008
CACTUS_USER_ID=@cactusbot:matrix.your-domain.com

Schritt 5: Docker Compose erweitern
#

In der bestehenden docker-compose.yml für Synapse füge ich den Cactus-Service hinzu:

cactus:
  image: cactuscomments/cactus-appservice:latest
  container_name: cactus
  env_file: cactus.env
  restart: unless-stopped
  networks:
    - synapse

Cactus landet im synapse-Netzwerk, damit es den Synapse-Container direkt unter http://synapse:8008 erreichen kann.

Schritt 6: Starten
#

cd ~/docker-compose/synapse
docker compose down
docker compose up -d synapse
# wait for Synapse to become healthy
docker compose up -d cactus

Zur Kontrolle:

docker logs cactus --tail 50
docker logs synapse --tail 50

Die Website bei Cactus registrieren
#

Bevor Cactus Kommentarräume für meinen Blog anlegen kann, muss ich meine Website beim cactusbot registrieren. Das geht direkt über Element:

Einen neuen Chat mit @cactusbot:matrix.your-domain.com öffnen und eingeben:

register <websitename>

Wenn alles korrekt eingerichtet ist, antwortet der Bot mit einer Bestätigung. In den Container-Logs sieht der erfolgreiche Ablauf so aus:

INFO in app: Registration complete
INFO in app: Created site    name='websitename' owner='@your_name:matrix.your-domain.com'
INFO in app: Power level changed, replicating    room='#comments_websitename:matrix.your-domain.com'

Hugo Integration
#

Client-Dateien kopieren
#

cd ~/hugo/cactus-client
cp dist/cactus.js ~/hugo/blog/static/
cp dist/style.css ~/hugo/blog/static/cactus.css

Shortcode erstellen
#

nvim ~/hugo/blog/layouts/shortcodes/chat.html

Mein Shortcode lädt den Cactus Client und initialisiert den Kommentarbereich. Ich habe ihn außerdem an mein Catppuccin-Farbschema angepasst – sowohl für den hellen Latte- als auch den dunklen Mocha-Modus:

<script type="text/javascript" src="/cactus.js"></script>
<link rel="stylesheet" href="/cactus.css" type="text/css" />
<style>
  /* Fix avatar image distortion */
  .cactus-comment-avatar img {
    max-width: unset;
    width: 40px;
    height: 40px;
    object-fit: cover;
  }
  /* Catppuccin Latte (Light) */
  :root[data-theme="light"] {
    --cactus-text-color: #4c4f69;
    --cactus-text-color--soft: #6c6f85;
    --cactus-background-color: transparent;
    --cactus-background-color--strong: #e6e9ef;
    --cactus-border-color: #ccd0da;
    --cactus-border-width: 1px;
    --cactus-border-radius: 0.5em;
    --cactus-box-shadow-color: rgba(30, 102, 245, 0.15);
    --cactus-button-text-color: #4c4f69;
    --cactus-button-color: #dce0e8;
    --cactus-button-color--strong: #ccd0da;
    --cactus-button-color--stronger: #bcc0cc;
    --cactus-login-form-text-color: #4c4f69;
    --cactus-error-color: #d20f39;
  }
  /* Catppuccin Mocha (Dark) */
  :root[data-theme="dark"] {
    --cactus-text-color: #cdd6f4;
    --cactus-text-color--soft: #a6adc8;
    --cactus-background-color: transparent;
    --cactus-background-color--strong: #313244;
    --cactus-border-color: #45475a;
    --cactus-box-shadow-color: rgba(137, 180, 250, 0.18);
    --cactus-button-text-color: #cdd6f4;
    --cactus-button-color: #45475a;
    --cactus-button-color--strong: #585b70;
    --cactus-button-color--stronger: #6c7086;
    --cactus-login-form-text-color: #cdd6f4;
    --cactus-error-color: #f38ba8;
  }
</style>
<br />
<div id="comment-section"></div>
<script>
  initComments({
    node: document.getElementById("comment-section"),
    defaultHomeserverUrl: "https://matrix.your-domain.com",
    serverName: "matrix.your-domain.com",
    siteName: "websitename",
    commentSectionId: "{{ index .Params 0 }}",
  });
</script>

Alle verfügbaren Konfigurationsoptionen für initComments sind in der Cactus Client Dokumentation beschrieben.

Kommentarbereich in einen Beitrag einbinden
#

Ab sofort reicht eine einzige Zeile, um unter einem Artikel einen Kommentarbereich hinzuzufügen:

{{< chat cactus-comments >}}

Der Parameter cactus-comments ist der Name des Matrix-Raums für diesen Artikel. Jeder Raum bekommt automatisch den Alias #comments_websitename_cactus-comments:matrix.your-domain.com. Ich kann für jeden Artikel einen eigenen Raumnamen verwenden oder denselben für alle – das hängt davon ab, ob man Kommentare pro Artikel oder global zusammenführen möchte.

Änderungen veröffentlichen
#

git add layouts/shortcodes/chat.html static/cactus.css static/cactus.js
git commit -m "migrate Cactus Comments to self-hosted matrix.your-domain.com"
git push origin

Fazit
#

Was mich an Cactus Comments überzeugt: Es gibt keine externe Datenbank, kein Drittanbieter-Tracking, keine JavaScript-Payloads von fremden Domains.

Die Kommentare liegen als gewöhnliche Matrix-Events in meinem eigenen Synapse – gesichert mit meinem üblichen restic-Backup, versioniert, portierbar.

Gleichzeitig kann jeder, der einen Matrix-Account hat, sofort kommentieren – ganz egal, auf welchem Homeserver sein Account liegt. Und wer noch keinen Account hat, kann sich in wenigen Minuten einen auf matrix.org anlegen.

Das ist das Web, wie es sein sollte.


Fragen oder Anmerkungen? Schreib mir direkt über Matrix: @sebastian:matrix.techlab.icu – oder hinterlasse einfach unten einen Kommentar. Der landet dann auch prompt in meiner Matrix.

Liebe Grüße
Sebastian

Verwandte Artikel

Eigener Matrix-Homeserver mit Synapse – Warum du deine Chats selbst hosten solltest

1583 Wörter·8 min· loading

Ollama Context Window optimieren: Der Schlüssel für erfolgreiche OpenCode Integration

1043 Wörter·5 min· loading

Hugo: Serien-Funktion für mehrteilige Blogposts

876 Wörter·5 min· loading

Die Herausforderung mehrsprachiger Blogs

1485 Wörter·7 min· loading

DD-WRT auf dem TL-WR949N installieren – der vollständige Leitfaden

1005 Wörter·5 min· loading

Rainy 75 Pro: So sieht meine perfekte Tastatur aus

·
1182 Wörter·6 min· loading

Kommentare
#