hachiflow.com

Cet article parle de Buzz, notre produit précédent. Aujourd'hui, nous construisons Waggle.

Migration

La porte de sortie est une fonctionnalité du produit

La plupart des plateformes hébergées prouvent leur verrouillage en rendant le départ douloureux. Nous avons répété le départ jusqu'à ce qu'il fonctionne depuis le README du paquet lui-même, sur une machine vierge, sans rien connaître de nos systèmes. Notes de terrain sur la migration dans les deux sens : vers l'hébergé quand l'ops vous fatigue, vers la sortie quand vous voulez les clés.

Pourquoi l'historique de chat est d'ordinaire pris en otage

Demandez vos données à une plateforme de chat hébergée et vous recevez d'ordinaire un fichier d'archives : un zip de JSON et de pièces jointes, très bien pour la conformité et pour grep, inutile pour poursuivre la conversation ailleurs. La communauté vivante, ce que vous avez réellement construit, ne sort pas. « Exporter vos données » et « partir avec votre communauté » sont deux promesses différentes, et la plupart du secteur ne tient que la première.

Buzz rend cet écart concret plutôt que commercial. Chaque message est signé par son auteur, et la signature couvre l'horodatage. Un relay n'accepte un événement que de la clé qui l'a signé, et seulement tant que l'horodatage est frais, environ quinze minutes avec le relay standard. Personne ne peut donc republier l'historique de l'an dernier vers un nouveau relay par le réseau : ni nous, ni vous, ni les personnes qui ont écrit les messages. Ce n'est pas une politique que nous pourrions assouplir ; c'est ainsi que le protocole se défend contre un historique falsifié ou rejoué, et cela s'impose à quiconque fait tourner Buzz, où que ce soit.

Nous l'avons appris honnêtement. Notre première conception de l'export supposait que des événements signés pouvaient être republiés vers n'importe quel relay ; une répétition l'a démenti, et nous avons corrigé nos propres textes. Depuis, l'export est une archive et le dit clairement. Cet article porte sur ce que nous avons construit au-delà : un chemin de migration qui déplace la communauté vivante dans les deux sens, sans prétendre que le réseau peut faire ce qu'il ne peut pas.

L'identité vit dans le hostname

Le second fait sur lequel tout repose : l'identité d'une communauté Buzz est soudée au hostname du relay. Quand un client se connecte, le relay détermine quelle communauté il sert d'après l'hôte par lequel la connexion est arrivée, et chaque message, chaque adhésion et chaque fichier est rattaché à l'identifiant interne de cette communauté. Le hostname n'est pas tant l'endroit où vit la communauté que la façon dont elle est nommée, et ce lien existe en un seul endroit : une ligne dans la base du relay, qui désigne l'hôte de la communauté.

Cette ligne est le pivot de toute la migration, et elle est aussi à l'origine du conseil que nous donnons désormais à tout le monde avant toute chose : choisissez votre hostname avec soin, dans les deux sens, avant que les gens n'emménagent. Cinquante membres plus tard, c'est le nom auquel répond votre communauté, et le changer est une migration, pas une case à cocher dans les réglages.

Restaurer, rattacher, démarrer

Comme le réseau est fermé au passé, la vraie migration se fait en dessous, dans la base de données. Trois étapes, et l'ordre est toute l'astuce : restaurer, rattacher, démarrer.

D'abord restaurer, relay encore à l'arrêt : chargez le dump dans une base vide, et répliquez les médias vers le nouveau stockage de médias. Dans Buzz, les médias sont adressés par leur contenu, nommés d'après le hash de leurs propres octets, et peu leur importe quel hostname les sert. Ensuite rattacher : mettez à jour cette unique ligne d'hôte avec le nouveau hostname. Ensuite, et seulement ensuite, démarrez le relay. Au lancement, il cherche une communauté à l'hôte configuré, trouve la ligne que vous avez rattachée et l'adopte : même communauté, même identifiant interne, historique complet, horodatages d'origine.

Démarrez d'abord et vous tombez sur l'échec qui fait croire que tout cela est impossible : le relay ne trouve aucune communauté à son hôte, en sème obligeamment une neuve et vide, et votre historique restauré reste dans la même base, orphelin à côté. Tout paraît sain et chaque canal est vide. Rattachez avant le premier démarrage et le relay n'a jamais l'occasion de se montrer serviable. Lors de nos répétitions, l'historique restauré était lisible via une connexion authentifiée dès que le relay était en ligne, et la même clé de propriétaire qui faisait tourner l'ancienne instance a publié de nouveaux messages sur la nouvelle.

ancien hôte auto-hébergé ou hébergé nouvel hôte hébergé ou auto-hébergé par le réseau refusé, pour tout le monde les horodatages signés expirent en minutes 1 · restaurer dump de la base + médias 2 · rattacher une ligne : l'hôte de la communauté 3 · démarrer le relay adopte la communauté rattacher avant le premier démarrage
Le réseau refuse l'historique rejoué pour tout le monde, la migration passe donc en dessous : restaurez le dump, rattachez la ligne d'hôte au nouveau nom, et démarrez seulement ensuite. Le relay adopte la communauté qu'il trouve au lieu d'en semer une vide.
restaurer, rattacher, démarrer
# relay à l'arrêt : chargez le dump, puis répliquez les médias $ pg_restore --no-owner -d <empty-db> community.dump # une ligne, avant le premier démarrage du relay $ psql -d <empty-db> \ -c "UPDATE communities SET host = 'chat.your-new-name.example'" # le relay adopte la communauté qu'il trouve à son hôte $ docker compose up -d relay

Tout le mécanisme, abrégé. L'ordre est l'astuce : un relay démarré avant le rattachement sème une communauté vide à son hostname, et votre historique restauré reste orphelin à côté.

Entrer : quand l'ops vous fatigue

Premier sens : l'entrée. Vous auto-hébergez Buzz, le charme des alertes disque à 2 h du matin s'est dissipé, et si vous n'avez pas bougé, c'est que déménager veut d'ordinaire dire repartir de zéro : nouveaux comptes, canaux vides, un lien « l'historique est dans l'ancien outil » que personne ne suit jamais. C'est le déménagement que nous avons répété de bout en bout cette semaine, avec les mêmes outils d'import que nous utiliserons pour votre communauté, et aucun de ces coûts n'a survécu à la répétition.

Ce qui a suivi, vérifié plutôt qu'espéré : l'historique complet, avec ses horodatages d'origine, parce qu'une restauration est une opération de base de données et que la fenêtre de quinze minutes du réseau n'a jamais voix au chapitre. Chaque identité de membre, sans aucune réinscription, parce qu'une identité Buzz est une paire de clés Nostr que détient le membre, et non un compte que nous émettons : les mêmes clés qui fonctionnaient avec votre hostname continuent de fonctionner avec le nouveau, et personne n'a à se réinscrire. Et les médias, octet pour octet, vérifiés par rapport à leurs adresses de contenu.

Ce que nous vous demandons est volontairement réduit : un dump de votre base et un moyen de lire votre stockage de médias. Nous faisons le reste nous-mêmes, avec une sauvegarde prise avant que l'import ne touche à quoi que ce soit, et la liste de contrôle de la répétition est déroulée avant que nous considérions le travail comme terminé. Il n'y a pas aujourd'hui de bouton d'import en libre-service, et nous ne sommes pas pressés d'en ajouter un : une migration est le seul jour où votre communauté mérite un opérateur pleinement attentif.

Sortir : quand vous voulez les clés

Second sens : la sortie. Chaque espace de travail hébergé a toujours pu télécharger un export : les événements signés, les médias, un README. C'est la couche d'archive, et elle assume d'être une archive. Ce que le paquet gagne désormais, c'est une couche souveraine à côté : le dump complet de la base, la référence exacte de l'image de conteneur que faisait tourner l'espace, un fichier compose, et un script de restauration qui impose restaurer, rattacher, démarrer, dans cet ordre.

Le critère auquel nous le soumettons est le seul qui compte : aucune aide de notre part. Lors de la répétition, une machine vierge qui n'avait jamais touché nos systèmes a suivi le README du paquet et est repartie en auto-hébergé sur un nouveau hostname. La même clé de propriétaire s'est connectée. L'historique complet était là. Les médias étaient servis à leurs adresses de contenu. Et l'instance acceptait de nouveaux messages, ce qui fait toute la différence entre une pièce de musée et une communauté qui a déménagé.

Un export que vous ne pouvez restaurer qu'avec l'éditeur au bout du fil n'est pas une porte, c'est une laisse avec des étapes en plus. Le README est donc la référence sur laquelle nous répétons : partir devrait être un après-midi ennuyeux passé à suivre des instructions qui fonctionnent. Nous préférons mériter votre ops plutôt que tenir la porte de sortie.

Les limites, sans détour

Un récit de migration sans ses limites est une publicité, les voici donc. Premièrement : les anciens messages qui embarquaient des URL absolues, miniatures dans des téléversements anciens, réponses de téléversement citant une adresse complète, pointent pour toujours vers l'ancien hostname. Ces URL vivent à l'intérieur de contenu signé, et réécrire du contenu signé serait une falsification : aucune migration honnête ne peut y toucher. Les fichiers médias eux-mêmes sont adressés par leur contenu et servis correctement depuis le nouvel hôte ; seules les URL littérales figées dans les anciens messages signés désignent encore l'endroit que vous avez quitté.

Deuxièmement, à la sortie : la clé de signature propre au relay ne part pas avec vous. Votre instance restaurée génère une nouvelle identité de relay, si bien que les notifications système signées par l'ancien relay restent attribuées à l'identité qui les a réellement signées, ce qui est précisément le rôle des signatures. L'accès des membres n'est pas affecté : chacun de vos membres est sa propre clé, et ces clés voyagent parce qu'elles n'ont jamais été à nous.

Troisièmement, dans les deux sens : choisissez le hostname de destination comme s'il était définitif, parce qu'il l'est en pratique. La même soudure qui rend suffisant le rattachement d'une seule ligne fait du hostname la seule chose que vous ne pourrez pas changer à la légère plus tard.

Le contrôle, dans les deux sens

Mettez tout bout à bout et la souveraineté cesse d'être un slogan pour devenir une liste de contrôle. Vos membres détiennent leurs propres clés, donc aucun opérateur, nous compris, ne s'interpose entre eux et leur identité. Votre historique se restaure sous un hostname que vous contrôlez, quel que soit le sens dans lequel vous partez. Le réseau refuse l'historique rejoué pour tout le monde à égalité, et le chemin par la base de données, en dessous, fonctionne pour tout le monde à égalité. Le contrôle n'est pas une impression dans une grille tarifaire ; c'est le fait que la porte de sortie ait été répétée jusqu'à ce qu'elle s'ouvre. La nôtre l'a été, cette semaine, à partir du seul README.

Où cela vous laisse

Le côté hébergé de l'affaire se trouve sur hachiflow.com : 50 $ par mois, forfaitaire, votre propre relay à name.hachiflow.chat, et la migration décrite ici, réalisée avec vous, en direct, quel que soit le sens dans lequel vous allez.

Et si vous ne nous versez jamais un dollar, prenez le mécanisme : restaurer, rattacher, démarrer, dans cet ordre, avec le rattachement avant le premier démarrage du relay. Cet ordre à lui seul constitue l'essentiel d'une migration Buzz. Nous l'avons prouvé sur une machine vierge cette semaine, et il est à vous.

← Toutes les notes