Zum Inhalt

Discourse

Was es tut

Discourse ist das Forum des Vereins: Mitglieder tauschen sich dort aus, Arbeitsgruppen und Werkstätten haben eigene Bereiche, und Ankündigungen erreichen alle per E-Mail. Es ist eine der zentralen Apps; die meisten Mitglieder nutzen es täglich.

Wo es liegt

Adresse https://forum.garage-lab.de
Host werner
Stack-Datei syslet/werner/stack-discourse.cue
Begleitmaterial apps/discourse/
Upstream discourse.org, Doku und Forum

Verwaltet über

Beides. Container, Anmeldung über Authentik und Mailversand stehen in der Stack-Datei bzw. in Terraform. Kategorien, Gruppenrechte, Themes und die meisten Einstellungen des Forums werden in der Admin-Oberfläche von Discourse gepflegt; Discourse speichert sie in seiner Datenbank.

Aufbau

flowchart LR
    caddy["Caddy"]

    subgraph stack ["Netzwerk discourse (intern)"]
        server["discourse-server"]
        db["discourse-postgres"]
        cache["discourse-valkey"]
        exp["discourse-postgres-exporter"]
    end

    shared[("discourse-server-data")]
    uploads[("discourse-server-uploads")]
    backups[("discourse-server-backups")]

    caddy -->|forum.garage-lab.de| server
    server --> db
    server --> cache
    exp --> db
    server --- shared & uploads & backups
  • discourse-server enthält die eigentliche App; im Container laufen ein Webserver und die Ruby-Anwendung zusammen. Wir nutzen ein eigenes Image (docker.io/garagelabdus/discourse) auf Basis des offiziellen, mit höheren Grenzen für viele gleichzeitige Anfragen (siehe Login / SSO).
  • discourse-postgres ist die Datenbank, im Image, das Discourse dafür vorsieht.
  • discourse-valkey hält Zwischenspeicher und Warteschlangen für Hintergrundaufgaben, etwa den Mailversand.
  • discourse-postgres-exporter liefert Messwerte der Datenbank für das Monitoring.

Die Volumes von discourse-server enthalten Konfiguration und Logs (-data), hochgeladene Dateien (-uploads) und die Backup-Archive (-backups). Mails verschickt Discourse über Mailjet (siehe Ausgehende E-Mails).

Login / SSO

Discourse ist auf zwei Wegen an Authentik angebunden:

OIDC für den Login (application_discourse.tf). Das Forum ist nur nach dem Login sichtbar. Die Kachel im App-Dashboard führt auf /login#autooidc; die Theme-Komponente aus apps/discourse/discourse-autooidc/ klickt dann selbst auf den Login-Knopf, sodass man direkt bei Authentik landet. Sie ist in der Admin-Oberfläche von Discourse installiert.

SCIM für die Konten (application_discourse_scim.tf). Authentik legt die Konten im Forum an, hält Name, E-Mail-Adresse und Gruppen aktuell und deaktiviert die Konten von Personen, die keinen Zugriff mehr haben. Übertragen werden nur Mitglieder der Gruppe „Discourse Access“ (group_filters); die Access-Gruppe bestimmt also nicht nur, wer sich anmelden darf, sondern auch, wer überhaupt ein Konto im Forum hat. Gruppen kommen unter ihrem app_group_name im Forum an, die Access-Gruppe selbst als Gruppe access (siehe Gruppenmodell in Authentik).

Bei einem vollständigen Abgleich schickt Authentik viele Anfragen gleichzeitig. Damit Discourse sie nicht als Angriff abweist, hat unser Image höhere Grenzen für die SCIM-Schnittstelle, und die Adressen von server.camp sind von der Begrenzung je Adresse ausgenommen (Kommentar in der Stack-Datei).

Administratoren im Forum werden nicht über Gruppen aus Authentik vergeben, sondern in Discourse selbst, mit Bestätigung per E-Mail. Für den Notfall gibt es einen Login für Administratoren ohne Authentik unter /u/admin-login.

Backup

Discourse legt selbst Archive mit Datenbank und hochgeladenen Dateien an, nach seinem eigenen Zeitplan, im Volume discourse-server-backups. Gesichert werden nur diese Archive, nicht die Volumes der Datenbank (siehe Backup).

Zurückgeholt wird ein solches Archiv über Discourse selbst. Danach müssen die Beiträge neu aufbereitet werden (rake posts:rebake_uncooked_posts); die Schritte stehen in App aus dem Backup wiederherstellen.

Updates

Die Version steht in image: discourse: tag: oben in der Stack-Datei. Weil wir ein eigenes Image nutzen, muss es für jede neue Version zuerst neu gebaut werden. Was sich ändert, steht in den Ankündigungen auf meta.discourse.org; vor jedem Update lesen (siehe Image-Version anheben).

Besonderheiten / bekannte Probleme

  • Hinter Caddy: Damit Discourse in Logs und Admin-Oberfläche die Adresse der Besucher sieht statt der von Caddy, wertet der nginx im Container X-Forwarded-For aus, aber nur von Adressen aus 10.0.0.0/8 (Datei 10-http.conf unter configFiles in der Stack-Datei; siehe Ingress mit Caddy).
  • Kurzbefehle auf werner: Für Shell, Rails-Konsole, Logs und Datenbank gibt es Kurzbefehle wie discourse-shell, discourse-railsc und discourse-psql in rootfs/werner/root/.bashrc (siehe Statische Konfiguration).
  • Testumgebung auf containerhost: syslet/containerhost/stack-discourse.cue war als Testumgebung gedacht, läuft aber nicht, weil containerhost dafür noch zu wenig Ressourcen hat; bisher legt die Datei nur ein Volume an.

Im Ordner apps/discourse/ liegt Begleitmaterial, das nicht ausgerollt wird:

  • hack/: Skripte für Konten ausgetretener Mitglieder (siehe Skripte in hack/)
  • maint/: eine statische Wartungsseite
  • discourse-autooidc/: die Theme-Komponente für den automatischen Login

Skripte in hack/

Die Python-Skripte in apps/discourse/hack/ arbeiten über die API von Discourse, etwa beim Austritt vieler Mitglieder. Sie brauchen einen API-Key von Discourse und rufen die API standardmäßig als Benutzer system auf (--api-username). Die Skripte, die etwas ändern, kennen --dry-run.

Skript Was es tut
suspend-users.py sperrt die Konten aus einer Austrittsliste (Spalten Discourse Username und Offboarding Date) für 100 Jahre mit dem Grund „Ausgetreten zum …“; die IDs der Konten kommen aus einem Benutzer-Export von Discourse (--users)
list-suspended-users.py listet alle gesperrten Konten, mit --csv als CSV; bereits anonymisierte Konten nur mit --include-anonymized
anonymize-users.py anonymisiert die Konten aus einer CSV von list-suspended-users.py; übersprungen werden Konten, deren Name nicht mehr passt oder die nicht mehr gesperrt sind. Lässt sich nicht rückgängig machen.
merge-anonymized-users.py führt anonymisierte Konten, die weniger als --posts-read-below Beiträge gelesen haben, im Konto ehemaliges_mitglied zusammen (--merge-target); Discourse erledigt das im Hintergrund. Lässt sich nicht rückgängig machen.
create-mx-statistics.py gruppiert die E-Mail-Adressen aus einer CSV (Spalte Email) nach Domain und deren Mailserver (MX)

Entscheidungen

Konten kommen per SCIM ins Forum, nicht erst beim ersten Login. Discourse hatte schon Konten, bevor der Login auf Authentik umgestellt wurde. Beim ersten Login über OIDC kennt Discourse die Zuordnung zwischen der ID der Person in Authentik (sub) und dem bestehenden Konto nicht und legt deshalb ein neues Konto an, etwa max1 neben max. Per SCIM überträgt Authentik diese Zuordnung vorab; der Login landet dann im richtigen, bestehenden Konto. Außerdem sperrt SCIM das Konto im Forum, sobald jemand keinen Zugriff mehr hat.

Wir nutzen ein eigenes Image. Das offizielle Image begrenzt gleichzeitige Anfragen so stark, dass der Abgleich per SCIM abgewiesen würde.

Weiterlesen