Embeds: Lädt nicht oder Thread wird nicht erstellt, keine Logs, was tun!

Im Laufe einiger Tage bemerkte ich, dass viele Leute nach Lösungen für Kommentar-Embeds gesucht und gepostet haben. Ich gehöre zu diesen Leuten. Ich hoffe, dieser Beitrag hilft anderen in der gleichen Situation.

Ich bin neu bei Discourse, daher kann jeder, der die von mir bereitgestellten Informationen mit tiefgreifendem Fachwissen ergänzen möchte, dies gerne tun.

Eines kann ich nach Überprüfung der vielen Beiträge zu diesem Thema sagen: Die Ursachen der Probleme können vielfältig sein. Für diejenigen in meiner Situation gibt es hier eine Lösung!

Problem

  1. Sie haben ein Einbettung, auf der steht „Diskussion wird geladen…“
  2. Discourse-Themen werden nicht automatisch erstellt.

Lösung

Versuchen Sie, Ihre Domain zur Liste der zulässigen internen Hosts hinzuzufügen.

Es handelt sich um eine Website-Einstellung im Bereich Admin. Sie finden sie unter diesem Pfad Ihrer Discourse-Website:

/admin/site_settings/category/all_results

Ein direkter Link zu der Einstellung, auf die ich mich beziehe, wäre:

/admin/site_settings/category/all_results?filter=allowed_internal_hosts

Für diejenigen, die die Rails-Konsole verwenden, suchen Sie nach:

SiteSetting.allowed_internal_hosts

Die Einstellung ist eine durch Pipe (|) getrennte Liste von Domainnamen.

Kontext

Meine Discourse-Instanz ist öffentlich, aber mein internes DNS löst einige Domains lokal auf. Dies kann in Setups mit Docker, Kubernetes oder jeder Umgebung mit internem DNS vorkommen.

Da ich neu bei Discourse bin, muss ich sagen, dass das, was jetzt offensichtlich erscheint, anfangs wirklich nicht offensichtlich war.

Diejenigen von uns, die mit den Interna von Discourse nicht vertraut sind, wissen nicht, dass 2017 ein SSRF-Schutz implementiert wurde oder auch nur die Details dieses Schutzes. Erst im Nachhinein wird diese Ankündigung klar.

Es ist eine gut implementierte Funktion, aber aus einem sehr einfachen Grund ein ziemlicher Kaninchenbau.

Was Sie wissen müssen

Discourse erstellt kein Thema für Ihre Einbettung, wenn die Domain auf eine lokale IP-Adresse aufgelöst wird.

Schreien Sie noch nicht, Leute. Das ist eine gute Sache. Sie können über SSRF lesen, um herauszufinden, warum, und den Discourse-Entwicklern dafür danken, dass sie es ernst nehmen.

Das Problem ist, dass Discourse kein Feedback gibt, um uns mitzuteilen, warum die Themen nicht erstellt werden und warum sie bei „Diskussion wird geladen…“ hängen bleiben.

Zusätzliche Lektüre

Aber was genau ist eine lokale IP-Adresse? Wer daran interessiert ist, kann die Antwort direkt im Discourse-Code finden. Hier ist ein direkter Link zur Datei auf GitHub.

Wenn Ihre Discourse-Instanz unter super-forum[dot]com beispielsweise in einem Netzwerk lebt, das auch cool-blog[dot]net hostet, löst Ihr internes DNS cool-blog[dot]net möglicherweise als lokale IP-Adresse auf – was Discourse ablehnt, es sei denn, es ist auf der Zulassungsliste.

Hoffentlich spart dieser Beitrag jemand anderem ein paar Stunden des Kopfzerbrechens – und vielleicht sogar ein paar Haare.

2 „Gefällt mir“

Als ich heute wieder zur Arbeit kam, fielen mir ein paar Dinge in den Admin-Seiten auf. Hier sind ein paar Gedanken, was verbessert werden könnte.

Einbettungseinstellungen — /admin/customize/embedding/settings

allowed_internal_hosts ist eine entscheidende Einstellung, damit die Einbettung in nicht-öffentlichen Umgebungen zuverlässig funktioniert. Sie sollte in diesem Abschnitt explizit als verwandte Einstellung aufgeführt werden – ihre Bedeutung steht außer Frage.

Einbettungs-Hosts — /admin/customize/embedding

Der bereitgestellte Konfigurationsausschnitt ist mehr als hilfreich, da er viele nützliche Informationen enthält. Ich denke, wir können ihn nutzen, um zusätzliche Anleitungen zu geben.

Erster Absatz

Aktuell:

Fügen Sie den folgenden HTML-Code in Ihre Website ein, um Discourse-Themen zu erstellen und einzubetten. Ersetzen Sie EMBED_URL durch die kanonische URL der Seite, auf der Sie ihn einbetten.

Alternative:

Fügen Sie den folgenden HTML-Code dort ein, wo die Kommentare auf Ihrer Seite erscheinen sollen.
Die discourseEmbedUrl ist die URL Ihrer Seite – diejenige, die von Discourse verlinkt wird. Wenn Ihre Seite zum ersten Mal geladen wird, versucht Discourse, ein Thema für diese URL zu finden oder zu erstellen und auf Ihre Inhalte zu verlinken.

Zweiter Absatz

Aktuell:

Wenn Sie den Stil anpassen möchten, kommentieren Sie die Zeile aus und ersetzen Sie CLASS_NAME durch eine CSS-Klasse, die im Eingebetteten CSS Ihres Themes definiert ist.

Alternative:

Verwenden Sie die className-Eigenschaft, um benutzerdefinierte Klassen zum <html>-Tag innerhalb des eingebetteten Iframes hinzuzufügen. Um es zu gestalten, gehen Sie zu /admin/customize/themes, klicken Sie auf die Schaltfläche Bearbeiten Ihres Themes, dann auf die Schaltfläche Code bearbeiten und wählen Sie Erweitert anzeigen. Fügen Sie Ihr benutzerdefiniertes CSS im Abschnitt Eingebettetes CSS hinzu.

Dritter Absatz

Aktuell:

Ersetzen Sie DISCOURSE_USERNAME durch den Discourse-Benutzernamen des Autors, der das Thema erstellen soll. Discourse sucht den Benutzer automatisch anhand des content-Attributs der <meta>-Tags mit dem name-Attribut discourse-username oder author. Der Parameter discourseUserName ist veraltet und wird in Discourse 3.2 entfernt.

Alternative:

Hinweis: Das Thema wird von einem echten Discourse-Benutzer erstellt – nicht von einem Anzeigenamen oder einer Autorenzeichenfolge. Es muss ein gültiges, vorhandenes Konto sein. Es gibt drei Möglichkeiten, welcher Benutzer verwendet wird:

  1. Standard-Fallback – eingestellt unter /admin/customize/embedding/posts_and_topics
  2. Pro-Host-Überschreibung – eingestellt unter /admin/customize/embedding/
  3. Pro-URL-Steuerung – fügen Sie ein <meta name="discourse-username" content="USERNAME">-Tag zu Ihrer Seite hinzu mit einem vorhandenen Discourse USERNAME

Nur der Benutzername eines vorhandenen Discourse-Benutzers funktioniert. Discourse greift auf den Standard des Hosts oder den globalen Standard zurück, wenn der Meta-Tag-Benutzer nicht gefunden wird. Die hier gezeigte Methode mit dem <meta>-Tag ermöglicht eine programmgesteuerte Pro-URL-Steuerung, welcher Discourse-Benutzer zum Erstellen des Themas verwendet wird. Sie können beispielsweise Blogbeitragsautoren auf Ihrer Website mit entsprechenden Discourse-Benutzerkonten abgleichen.

Der Abschnitt Konfigurationsausschnitt

Der einklappbare Abschnitt „Konfigurationsausschnitt“ wird leicht übersehen. Visuell ähnelt er einer Überschrift, und der dezente Pfeil ist nicht intuitiv. Im Gegensatz zum Link „Mehr erfahren“, der farbig und auffällig ist, wirkt dieser wie versteckt im Sichtfeld.

Ich weiß, das mag diskutabel sein – einige mögen das UI als sauber und ausreichend empfinden. Aber ich habe diesen Abschnitt persönlich viel zu oft übersehen, bevor ich merkte, dass er klickbar war. Das sagt mir, dass die Benutzerfreundlichkeit verbessert werden könnte, wenn auch nur geringfügig. Ein klarerer visueller Hinweis oder eine nicht eingeklappte Standardansicht könnte viel bewirken, besonders für Neulinge, die auf Beispiele angewiesen sind.

Der Ausschnitt

Aktuell:

<div> id='discourse-comments'></div>
  <meta name='discourse-username' content='DISCOURSE_USERNAME'>

  <script type="text/javascript">
    DiscourseEmbed = {
      discourseUrl: 'https://discourse.your-site.com/',
      discourseEmbedUrl: 'EMBED_URL',
      // className: 'CLASS_NAME',
    };

    (function() {
      var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
      d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
    })();
  </script>

Alternative:

<div id="discourse-comments"></div>
<!-- Optional: specify which Discourse user account creates the topic -->
<!-- If omitted, Discourse falls back to the per-host or global default user -->
<meta name="discourse-username" content="DISCOURSE_USERNAME" />

<script type="text/javascript">
  DiscourseEmbed = {
    discourseUrl: 'https://discourse.mydomain.com/', // Trailing slash required
    discourseEmbedUrl: window.location.href, // Or a hardcoded canonical URL string
    // className: 'my-iframe-theme another-class',
    // discourseReferrerPolicy: 'strict-origin-when-cross-origin',
    // topicId: '1234',
  };

  (function() {
    const d = document.createElement('script');
    d.type = 'text/javascript';
    d.async = true;
    d.src = `${DiscourseEmbed.discourseUrl}javascripts/embed.js`;
    document.head.appendChild(d);
  })();
</script>

DiscourseEmbed-Optionen – Kurzbeschreibungen

  • discourseUrlErforderlich
    Die vollständige URL Ihrer Discourse-Instanz. Muss mit einem Schrägstrich enden, z. B. https://discourse.mydomain.com/

  • discourseEmbedUrlErforderlich
    Die vollständige URL der aktuellen Seite, auf der die Kommentare eingebettet werden. So identifiziert und verknüpft Discourse Themen mit Ihren Inhalten.

  • classNameOptional
    Fügt dem <html>-Element innerhalb des Iframes benutzerdefinierte CSS-Klassen hinzu. Definieren Sie Stile im Abschnitt „Eingebettetes CSS“ Ihres Discourse-Themes.

  • discourseReferrerPolicyOptional
    Standardmäßig no-referrer-when-downgrade. Siehe: Referrer-Policy

  • topicIdOptional
    Wenn gesetzt, verwendet Discourse dieses Thema direkt. Andernfalls sucht es nach einem Thema, das discourseEmbedUrl entspricht, oder erstellt eines, wenn keines vorhanden ist.

DiscourseEmbed kontextbezogene Dokumentation

Die discourseEmbedUrl muss für Ihren Discourse-Server zugänglich sein. Wenn der Iframe geladen wird, ruft Discourse die Seite unter dieser URL ab, um das Thema zu erstellen oder zu finden. Dies funktioniert nahtlos für Websites, die auf öffentlichen Plattformen gehostet werden.

Wenn Sie jedoch lokal entwickeln, wird die Einbettung möglicherweise mit „Diskussion wird geladen…“ hängen bleiben oder gar nicht erst erscheinen. Das liegt daran, dass lokale Entwicklungs-URLs (wie localhost) durch den SSRF-Schutz von Discourse, die Option force_https oder einen fehlenden einbettbaren Host blockiert werden können.

Wenn Sie neue Funktionen für eine bestehende Website erstellen, ist eine Problemumgehung, discourseEmbedUrl auf die Produktions-URL zu verweisen. Wenn embed_any_origin aktiviert ist, erlaubt Discourse die Einbettung auch dann, wenn der Iframe von einem anderen Ursprung aus bedient wird. Kommentare werden geladen, wenn sie vorhanden sind, oder es wird ein Button „Diskussion fortsetzen“ angezeigt.

Alternativ, wenn Ihre lokale Domain (z. B. localhost) unter Einbettungs-Hosts aufgeführt ist, benötigen Sie embed_any_origin möglicherweise gar nicht. Sie müssen localhost jedoch immer noch als einbettbaren Host hinzufügen.

:warning: Eine Einschränkung: Wenn die Einstellung force_https aktiviert ist und Ihre Entwicklungsumgebung kein TLS verwendet, schlägt die Einbettung fehl. In diesem Fall deaktivieren Sie entweder force_https während der Entwicklung oder erwägen Sie, eine separate Discourse-Instanz für Tests einzurichten.

Hinweis: Wenn discourseEmbedUrl öffentlich zugänglich ist und die Einbettung immer noch „Diskussion wird geladen…“ anzeigt, ohne ein Thema zu erstellen, wird Ihre Domain möglicherweise durch den SSRF-Schutz von Discourse blockiert.

Dies geschieht oft, wenn Ihre Discourse-Instanz in einer Umgebung mit lokaler DNS-Auflösung ausgeführt wird – wie Docker, Kubernetes oder ein LAN mit einem internen DNS-Server. In diesen Fällen kann Discourse die Domain Ihrer Website auf eine lokale IP-Adresse (z. B. 127.0.0.1 oder 192.168.x.x) auflösen und sie als unsicher einstufen.

Um den Zugriff zu ermöglichen, fügen Sie Ihre Domain zur Website-Einstellung allowed_internal_hosts hinzu. Dies kennzeichnet Ihre Domain explizit als sicher zum Abrufen und umgeht die SSRF-Filterung.

Die vollständige Liste der blockierten IP-Bereiche finden Sie im Quellcode von Discourse.

Erlaubte interne Hosts – [Beschreibung der Website-Einstellung]((/admin/customize/embedding/settings`)

Aktuell:

Eine Liste interner Hosts, die Discourse sicher für Oneboxing und andere Zwecke crawlen kann

Alternative:

Ermöglicht Discourse das Crawlen von Hosts, die auf interne IPs aufgelöst werden. Benötigt, wenn Ihre Website hinter lokaler DNS läuft (z. B. Docker, LAN, Kubernetes). Erforderlich für Kommentar-Einbettungen, Themenerstellung und Oneboxing, wenn der SSRF-Schutz den Zugriff sonst blockieren würde.

Überlegungen

Einige dieser Vorschläge eignen sich möglicherweise besser als Links zur offiziellen Dokumentation. Tatsächlich könnte dieser Beitrag allein seinen Zweck erfüllen, da er wie jeder andere indexiert werden sollte. Andere könnten einen ordnungsgemäßen Pull-Request rechtfertigen – an dem ich vielleicht irgendwann arbeiten werde, nur nicht heute.

Dennoch kann es technische Ungenauigkeiten in dem geben, was ich geschrieben habe. Das meiste davon stammt aus praktischer Erfahrung, aber ich könnte ein Verhalten falsch interpretiert, mich von Caching täuschen lassen (oh, Caching…) oder einfach etwas übersehen haben. In dieser Hinsicht überlasse ich das Wort den erfahrenen Discourse-Veteranen.