Ğchange

Déploiement serveur

Faire tourner un nœud, un relai et la passerelle sur un serveur (NixOS).

Contenu généré par IA. Cette page a été rédigée avec l’aide d’une IA et n’a pas encore été entièrement relue — elle peut comporter des imprécisions.

Cette page décrit un déploiement serveur complet à partir du flake Nix du dépôt : l’indexeur (trame-noded), le relai (trame-relay), la passerelle HTTP (trame-gateway, optionnelle), et le service des ressources statiques (le bundle web et ce site). Pour simplement installer un pod clé en main, voir plutôt Serveur.

Les composants

Composant Rôle Exposé sur
trame-noded nœud p2p : stocke et indexe la donnée, se synchronise via iroh rien en entrée (sort en UDP/QUIC)
trame-relay relai iroh pour les clients sans UDP direct (navigateur web, NAT strict) HTTP(S)/WebSocket
trame-gateway passerelle HTTP : sert un bloc par CID (/ipfs/<cid>), permaliens inspectables sans charger l’app ; découplée (store propre, résout les CID absents via le ticket du nœud) HTTP
bundle web + ce site fichiers statiques HTTP(S)

Le flake expose tout : packages.trame-noded / trame-relay / trame-gateway, les images OCI (oci-image, relay-oci-image, gateway-oci-image), packages.site, et les modules NixOS nixosModules.trame-noded / trame-relay / trame-gateway.

Prérequis (flake)

Ajoutez le dépôt comme entrée de votre configuration NixOS :

{
  inputs.trame.url = "git+https://git.duniter.org/HugoTrentesaux/datapod";
  # ... puis dans les modules de l'hôte :
  imports = [
    inputs.trame.nixosModules.trame-noded
    inputs.trame.nixosModules.trame-relay
  ];
}

Nœud indexeur (trame-noded)

services.trame-noded = {
  enable = true;
  # dataDir : état du nœud (blocs + index). Défaut /var/lib/trame-noded.
  network = "g1";              # étiquette de réseau gossip (topic des annonces)
  wan = true;                  # profil complet (relais + découverte iroh)
  admin = "<clé-publique-admin>";       # gouvernance : la seule clé de confiance à l'amorçage
  stateCar = "/chemin/genesis.car";     # état de référence initial (optionnel)
  follow = [ "<ticket-de-pair>" ];      # pairs à suivre (resync périodique)
  relay = "https://relay.exemple.org";  # se rend joignable via CE relais (clients web)
  ticketFile = "/run/trame-noded/node.ticket";  # publie son ticket (pour la passerelle / le build web)
  # listenPort = 4001; openFirewall = true;  # pour un port UDP fixe reproductible
};

Le nœud n’expose aucun port entrant à ouvrir : il sort en UDP/QUIC et passe par les relais iroh en wan. Options complètes : voir nix/trame-noded-module.nix.

Amorcer avec des données : stateCar ou carDir/importCars

Deux mécanismes distincts pour démarrer peuplé — ne pas les confondre :

Option Drapeau Effet
stateCar --state Adopte un CAR verbatim : son root devient le root du nœud (O(1), sans re-dérivation). C’est l’arbre entier initial — données + éventuelle charte d’admission signée déjà incluses → nœud conforme dès le boot. Le CAR doit être une racine de nœud (geopod-base).
carDir / importCars --car-dir / --import-car Fusionne des CAR de données brutes par-dessus l’état courant (chargement forcé, sans re-validation). N’apporte pas de charte — variante « données seules ». Accepte aussi un arbre d’index nu (geopod-index).

Règle simple : stateCar = état de référence complet (une seule racine adoptée), carDir = ajouter des données par-dessus. stateCar est appliqué avant les fusions. Voir aussi la génération de ces CAR.

Relai (trame-relay) — deux montages

Le relai parle HTTP/WebSocket. Deux cas :

A. Le serveur dédie 80/443 au relai (TLS natif)

Le relai gère lui-même le certificat :

services.trame-relay = {
  enable = true;
  hostname = "relay.exemple.org";
  tlsCert = "/var/lib/acme/relay.exemple.org/fullchain.pem";
  tlsKey  = "/var/lib/acme/relay.exemple.org/key.pem";
  openFirewall = true;         # ouvre 80/443
};

B. Un reverse-proxy occupe déjà 80/443 (recommandé ici) — sous-domaine dédié

C’est le cas quand Caddy (ou nginx) tient déjà 80/443 sur l’hôte. Un sous-domaine dédié au relai règle le conflit : le relai tourne en plaintext sur un port local, et le reverse-proxy termine le TLS et relaie le WebSocket.

services.trame-relay = {
  enable = true;
  httpBind = "127.0.0.1:8090";  # plaintext, local uniquement
  # pas de tlsCert/tlsKey, pas d'openFirewall : c'est Caddy qui expose
};

Caddy (le sous-domaine relay.exemple.org → relai local) :

relay.exemple.org {
    reverse_proxy 127.0.0.1:8090
}

Caddy obtient le certificat automatiquement et transmet le WebSocket de façon transparente ; les clients (navigateur) se connectent en wss://relay.exemple.org. C’est cette URL qu’on met dans le TRAME_RELAY de la flavor de l’app web.

Passerelle HTTP (trame-gateway, optionnelle)

Utile pour des permaliens inspectables https://…/ipfs/<cid> sans charger l’app (le modèle par défaut étant que le navigateur fait tourner un nœud WASM).

Modèle découplé (ne PAS partager le répertoire du nœud). La passerelle ouvre son propre répertoire de données, qu’elle doit pouvoir écrire : à l’ouverture, elle y pose ses schémas d’amorçage et son fichier root. Un montage/dossier en lecture seule échoue (Read-only file system, puis Permission denied) — c’est le piège à éviter. Elle ne lit pas le store du nœud : pour servir un CID qu’elle n’a pas, elle le résout via iroh en suivant le ticket du nœud (peers / peerFile), rapatrie le bloc dans son propre store, puis le sert. Nœud et passerelle sont donc deux services indépendants reliés par le réseau, pas par un dossier.

Course au démarrage. peerFile n’est lu qu’une fois, au boot. Démarrez la passerelle après que le nœud a écrit son ticket : pointez services.trame-noded.ticketFile et services.trame-gateway.peerFile sur le même chemin, et ordonnancez l’unité passerelle après le nœud (after). Sinon la résolution réseau reste désactivée jusqu’au prochain redémarrage.

Module NixOS (nixosModules.trame-gateway), derrière Caddy :

services.trame-noded.ticketFile = "/run/trame-noded/node.ticket";  # le nœud publie son ticket

services.trame-gateway = {
  enable = true;
  # dataDir : store PROPRE, inscriptible. Défaut /var/lib/trame-gateway (géré).
  peerFile = "/run/trame-noded/node.ticket";  # suit le ticket du nœud pour résoudre les CID
  bind = "127.0.0.1";               # local ; Caddy expose
  publicHost = "ipfs.exemple.org";  # isolation par sous-domaine <cid>.ipfs.<host>
};

# Démarrer après le nœud (le ticket doit exister quand la passerelle boote) :
systemd.services.trame-gateway = {
  after = [ "trame-noded.service" ];
  wants = [ "trame-noded.service" ];
};
ipfs.exemple.org {
    reverse_proxy 127.0.0.1:8480
}

Image OCI équivalente : gateway-oci-image (monter un /data inscriptible, passer le ticket du nœud en --peer/--peer-file, publier le port 8480).

Servir le bundle web et ce site (statiques)

Les deux sont des fichiers statiques :

exemple.org {
    root * /var/www/site        # nix build .#site
    file_server
}

app.exemple.org {
    root * /var/www/web         # geopod-web.tar.gz décompressé
    file_server
    try_files {path} /index.html
}

Le build web (nix run .#build-web) est actuellement impur (toolchain nightly + réseau, hors sandbox Nix) : côté infra, s’appuyer sur l’asset geopod-web.tar.gz de la release (fetché par hash) plutôt que sur une dérivation. Une dérivation pure est prévue.

Chaîne bout-en-bout : navigateur → relai → nœud

Un navigateur n’a pas d’UDP direct : pour qu’une app web rejoigne un nœud, le relai sert de point de rendez-vous WebSocket. Les trois briques se câblent ainsi :

  1. Le nœud s’annonce via le relai. services.trame-noded.relay = "https://relay.exemple.org" : le nœud se rend joignable par ce relai. Il publie aussi son ticket (ticketFile).
  2. Le relai termine le TLS derrière Caddy. Il tourne en plaintext local (httpBind = "127.0.0.1:8090"), Caddy expose wss://relay.exemple.org (section Relai B).
  3. L’app web est buildée avec le relai + le ticket du nœud. Le bundle statique fige GC_SYNC=wss://relay.exemple.org|<ticket-du-nœud> (ou l’équivalent flavor TRAME_RELAY + TRAME_BOOTSTRAP), cf. Démo web. Le ticket est celui écrit par le nœud dans ticketFile.
navigateur (app web, nœud WASM)
   │  wss://relay.exemple.org   (GC_SYNC = relais | ticket, figé au build)
   ▼
Caddy ──► trame-relay (127.0.0.1:8090, plaintext)
   │  relaie le canal iroh
   ▼
trame-noded  (relay = https://relay.exemple.org, joignable via le relai)

Résultat : l’app web démarre peuplée (sync initiale via le relai) et se met à jour, sans qu’aucun port UDP ne soit exposé.

Récapitulatif DNS

Nom Cible Sert
exemple.org Caddy → .#site le site de présentation
app.exemple.org Caddy → bundle web l’app web (nœud WASM)
relay.exemple.org Caddy → 127.0.0.1:8090 le relai iroh (wss)
ipfs.exemple.org Caddy → 127.0.0.1:8480 la passerelle (permaliens par CID, optionnel)

Le nœud indexeur, lui, n’a pas besoin d’entrée DNS entrante.