Embeds : bloqué au chargement ou sujet non créé et pas de logs, que faire !

Au cours de quelques jours, j’ai remarqué que beaucoup de gens avaient recherché et posté des solutions concernant les intégrations de commentaires. Je fais partie de ces personnes. J’espère que ce post aidera d’autres personnes dans la même situation.

Je suis nouveau sur Discourse, donc toute personne souhaitant compléter les informations que je fournis avec une expertise approfondie est libre de le faire.

Une chose que je peux dire après avoir examiné de nombreux posts sur le sujet est que la source des problèmes peut être très variée. Pour ceux qui sont dans ma situation, voici une solution !

Problème

  1. Vous vous retrouvez avec une intégration qui dit “Chargement de la discussion…”
  2. Les sujets Discourse ne sont pas créés automatiquement

Solution

Essayez d’ajouter votre domaine à la liste des hôtes internes autorisés.

C’est un paramètre de site trouvé dans la zone admin. Vous pouvez les trouver à ce chemin de votre site Discourse :

/admin/site_settings/category/all_results

Un lien direct vers le paramètre auquel je fais référence serait :

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

Pour ceux d’entre vous qui regardent la console Rails, regardez :

SiteSetting.allowed_internal_hosts

Le paramètre est une liste de noms de domaine séparés par une barre verticale (|).

Contexte

Mon instance Discourse est publique, mais mon DNS interne résout certains domaines localement. Cela peut se produire dans des configurations utilisant Docker, Kubernetes ou tout environnement avec DNS interne.

Étant nouveau sur Discourse, je dois dire que ce qui semble évident maintenant ne l’était vraiment pas au départ.

Ceux d’entre nous qui ne connaissent pas les rouages de Discourse ne savent pas qu’en 2017, une protection SSRF a été implémentée ni même les spécificités de cette protection. Ce n’est qu’avec le recul que cette annonce rend le lien clair.

C’est une fonctionnalité bien implémentée, mais c’était un véritable casse-tête pour une raison très simple.

Ce que vous devez savoir

Discourse ne créera pas de sujet pour votre intégration si le domaine se résout en une adresse IP locale.

Ne criez pas encore, les amis. C’est une bonne chose. Vous pouvez lire sur le SSRF pour savoir pourquoi et remercier les développeurs de Discourse de le prendre au sérieux.

Le problème est que Discourse ne fournit pas de retour d’information pour nous faire savoir pourquoi il ne crée pas les sujets et pourquoi il est bloqué sur “Chargement de la discussion…”

Lecture supplémentaire

Mais qu’est-ce qu’une adresse IP locale exactement ? Pour ceux qui sont intéressés, vous pouvez trouver la réponse directement dans le code de Discourse, voici un lien direct vers le fichier sur GitHub.

Par exemple, si votre instance Discourse à super-forum[dot]com se trouve sur un réseau qui héberge également cool-blog[dot]net, votre DNS interne pourrait résoudre cool-blog[dot]net comme une adresse IP locale, ce que Discourse rejettera à moins qu’elle ne soit autorisée.

J’espère que ce post fera économiser à quelqu’un d’autre quelques heures de casse-tête, et peut-être même quelques cheveux.

2 « J'aime »

En retournant au travail aujourd’hui, quelques éléments ont retenu mon attention dans les pages d’administration. Voici quelques réflexions sur ce qui pourrait être amélioré.

Paramètres d’intégration — /admin/customize/embedding/settings

allowed_internal_hosts est un paramètre crucial pour que l’intégration fonctionne de manière fiable dans des environnements non publics. Il devrait être explicitement répertorié comme un paramètre connexe dans cette section — son importance est indiscutable.

Hôtes d’intégration — /admin/customize/embedding

L’ extrait de configuration fourni est plus qu’utile car il contient de nombreuses informations précieuses. Je pense que nous pouvons l’utiliser pour fournir des conseils supplémentaires.

Premier paragraphe

Actuel :

Collez le code HTML suivant sur votre site pour créer et intégrer des sujets Discourse. Remplacez EMBED_URL par l’URL canonique de la page sur laquelle vous l’intégrez.

Alternative :

Collez le code HTML suivant là où vous souhaitez que les commentaires apparaissent sur votre page.
L’discourseEmbedUrl est l’URL de votre page — celle qui sera liée depuis Discourse. Lorsque votre page est chargée pour la première fois, Discourse tentera de trouver ou de créer un sujet pour cette URL et de renvoyer vers votre contenu.

Deuxième paragraphe

Actuel :

Si vous souhaitez personnaliser le style, décommentez et remplacez CLASS_NAME par une classe CSS définie dans le CSS intégré de votre thème.

Alternative :

Utilisez la propriété className pour ajouter des classes CSS à la balise <html> à l’intérieur de l’iframe intégré. Pour le styliser, allez dans /admin/customize/themes, cliquez sur le bouton Modifier de votre thème, puis sur le bouton Modifier le code, et cochez Afficher les options avancées. Ajoutez votre CSS personnalisé dans la section CSS intégré.

Troisième paragraphe

Actuel :

Remplacez DISCOURSE_USERNAME par le nom d’utilisateur Discourse de l’auteur qui doit créer le sujet. Discourse recherchera automatiquement l’utilisateur par l’attribut content des balises <meta> dont l’attribut name est défini sur discourse-username ou author. Le paramètre discourseUserName a été déprécié et sera supprimé dans Discourse 3.2.

Alternative :

Remarque : Le sujet est créé par un véritable utilisateur Discourse — pas un nom d’affichage ou une chaîne d’auteur. Il doit s’agir d’un compte valide et existant. Il existe trois façons de déterminer quel utilisateur est utilisé :

  1. Solution de repli par défaut — définie dans /admin/customize/embedding/posts_and_topics
  2. Remplacement par hôte — défini dans /admin/customize/embedding/
  3. Contrôle par URL — ajoutez une balise <meta name="discourse-username" content="USERNAME"> à votre page avec un USERNAME Discourse existant

Seul le nom d’utilisateur d’un utilisateur Discourse existant fonctionnera. Discourse utilisera la solution de repli au niveau de l’hôte ou la valeur par défaut globale si la balise meta n’est pas trouvée. La méthode de balise <meta> illustrée ici permet un contrôle programmatique, par URL, de l’utilisateur Discourse utilisé pour créer le sujet. Par exemple, vous pouvez mapper les auteurs d’articles de blog sur votre site à des comptes d’utilisateurs Discourse correspondants.

La section Extrait de configuration

La section “Extrait de configuration” déroulante est facile à manquer. Visuellement, elle ressemble à un titre, et la flèche subtile n’est pas intuitive. Contrairement au lien “En savoir plus”, qui est coloré et accrocheur, celui-ci semble caché à la vue de tous.

Je sais que cela peut être discutable — certains peuvent estimer que l’interface utilisateur est épurée et suffisante. Mais j’ai personnellement manqué cette section bien trop souvent avant de réaliser qu’elle était cliquable. Cela me dit que l’affordance pourrait être améliorée, même légèrement. Un indice visuel plus clair ou un état déplié par défaut pourrait faire beaucoup, surtout pour les nouveaux venus qui s’appuient sur des exemples.

L’Extrait

Actuel :

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

Options DiscourseEmbed — descriptions courtes

  • discourseUrlRequis
    L’URL complète de votre instance Discourse. Doit se terminer par une barre oblique, par exemple https://discourse.mydomain.com/

  • discourseEmbedUrlRequis
    L’URL complète de la page actuelle où les commentaires sont intégrés. C’est ainsi que Discourse identifie et lie les sujets à votre contenu.

  • classNameOptionnel
    Ajoute des classes CSS personnalisées à l’élément <html> à l’intérieur de l’iframe. Définissez les styles dans la section “CSS intégré” de votre thème Discourse.

  • discourseReferrerPolicyOptionnel
    Par défaut no-referrer-when-downgrade. Voir : Referrer-Policy

  • topicIdOptionnel
    S’il est défini, Discourse utilisera directement ce sujet. Sinon, il recherchera un sujet correspondant à discourseEmbedUrl, ou en créera un s’il n’en existe aucun.

Documentation contextuelle DiscourseEmbed

L’discourseEmbedUrl doit être accessible à votre serveur Discourse. Lorsque l’iframe est chargé, Discourse récupère la page à cette URL pour créer ou localiser le sujet. Cela fonctionne de manière transparente pour les sites web hébergés sur des plateformes publiques.

Cependant, si vous développez localement, l’intégration peut sembler bloquée sur “Chargement de la discussion…” ou ne pas apparaître du tout. C’est parce que les URL de développement locales (comme localhost) peuvent être bloquées par la protection SSRF de Discourse, ou l’option force_https, ou un hôte intégrable manquant.

Si vous créez de nouvelles fonctionnalités pour un site existant, une solution de contournement consiste à pointer discourseEmbedUrl vers l’URL de production. Lorsque embed_any_origin est activé, Discourse permettra à l’intégration de fonctionner même si l’iframe est servi depuis une origine différente. Les commentaires se chargeront s’ils existent, ou un bouton “Continuer la discussion” sera affiché.

Alternativement, si votre domaine local (par exemple, localhost) est ajouté sous Hôtes d’intégration, vous n’aurez peut-être pas besoin de embed_any_origin du tout. Mais vous devez toujours ajouter localhost comme hôte intégrable.

:warning: Une mise en garde : si le paramètre force_https est activé et que votre site de développement n’utilise pas TLS, l’intégration échouera. Dans ce cas, désactivez force_https pendant le développement ou envisagez de lancer une instance Discourse distincte pour les tests.

Remarque : Si discourseEmbedUrl est accessible publiquement et que l’intégration affiche toujours “Chargement de la discussion…” sans créer de sujet, votre domaine peut être bloqué par la protection SSRF de Discourse.

Cela se produit souvent lorsque votre instance Discourse s’exécute dans un environnement avec résolution DNS locale — comme Docker, Kubernetes, ou un réseau local avec un serveur DNS interne. Dans ces cas, Discourse peut résoudre le domaine de votre site à une adresse IP locale (par exemple, 127.0.0.1 ou 192.168.x.x) et la considérer comme non sécurisée.

Pour autoriser l’accès, ajoutez votre domaine au paramètre de site allowed_internal_hosts. Cela marque explicitement votre domaine comme sûr à récupérer, contournant le filtrage SSRF.

La liste complète des plages d’adresses IP bloquées est disponible dans le code source de Discourse.

Hôtes internes autorisés — [Description du paramètre de site]((/admin/customize/embedding/settings`)

Actuel :

Une liste d’hôtes internes que Discourse peut explorer en toute sécurité pour le oneboxing et d’autres usages

Alternative :

Permet à Discourse d’explorer les hôtes qui se résolvent en adresses IP internes. Nécessaire si votre site fonctionne derrière un DNS local (par exemple, Docker, LAN, Kubernetes). Requis pour l’intégration de commentaires, la création de sujets et le oneboxing lorsque la protection SSRF bloquerait autrement l’accès.

Considérations

Certaines de ces suggestions pourraient mieux convenir comme liens vers la documentation officielle. En fait, ce message à lui seul pourrait suffire, car il devrait être indexé comme n’importe quel autre. D’autres pourraient justifier une demande de tirage appropriée — que je pourrais éventuellement faire, mais pas aujourd’hui.

Cela dit, il peut y avoir des inexactitudes techniques dans ce que j’ai écrit. La plupart provient de l’expérience pratique, mais j’aurais pu mal interpréter un comportement, être dupé par la mise en cache (oh, la mise en cache…), ou simplement avoir négligé quelque chose. Sur ce point, je m’en remets aux vétérans chevronnés de Discourse.