Aller au contenu

Faire tourner un nœud OpenFiat

Les opérateurs de nœuds maintiennent le marché décentralisé qui repose au-dessus de la blockchain. Les validateurs Solana sécurisent la chaîne et exécutent les programmes OpenFiat ; les nœuds portent les annonces, la réputation, la messagerie et la découverte.

Les commandes ci-dessous utilisent le déploiement de référence : le service openfiat-node, /etc/openfiat pour la configuration et /var/lib/openfiat pour les données.

Matériel

Minimum

4 cœurs de CPU · 16 Go de RAM · SSD NVMe de 250 Go · Connexion haut débit stable

Recommandé pour la production

8–16 cœurs de CPU · 32 Go de RAM ou plus · SSD NVMe de 1 To · Réseau à grande bande passante et faible latence · Protection d’alimentation par onduleur (UPS) · Connectivité internet redondante

Le nœud est un unique binaire Rust. libp2p (QUIC, Noise, Yamux) et RocksDB sont compilés dedans — il n’y a rien à installer séparément.

Où le faire tourner

AllenHark mène le développement initial du protocole et vend les deux choses dont un nœud a besoin : un serveur et un accès RPC à Solana. Les opérateurs de nœuds bénéficient de 50 % de remise sur les deux, dans le cadre du programme OpenFiat.

Hébergement de serveurs

Stockage NVMe sur liens 10 Gbps, à Francfort, Amsterdam et Chicago. Dimensionnez d’après le matériel ci-dessus — le stockage est ce qu’un nœud complet finit par exiger, alors indiquez ce que vous faites tourner et il pourra être spécifié pour vous.

Voir les tarifs

RPC et gRPC Solana

Connexions avec stake, pour que les transactions envoyées par votre nœud ne fassent pas la queue derrière celles de tout le monde. L’accès est accordé par liste blanche d’IP plutôt que par une clé d’API. Yellowstone gRPC est disponible pour diffuser les mises à jour de comptes et de slots.

Voir les tarifs

Obtenir la remise

Aucun code à saisir. Demandez sur Discord ou dans le chat sur allenhark.com, dites que vous faites tourner un nœud OpenFiat, et la remise est appliquée à votre commande.

Servez le réseau, pas seulement vous-même

Un nœud qui ne fait que lire est un invité. Un nœud que le public peut atteindre est une infrastructure — portefeuilles, explorateurs et apps web doivent parler à *quelqu’un*, et aujourd’hui ces quelqu’un sont rares. Chaque opérateur qui place son nœud derrière TLS et définit --public-rpc-url élargit cet ensemble, ce qui fait la différence entre un réseau avec plusieurs portes d’entrée indépendantes et un réseau avec un point de défaillance unique dont tout le monde dépend en silence. Cela coûte un certificat et un reverse proxy. C’est aussi rémunéré : un nœud atteignable est un nœud que les pairs peuvent défier et récompenser, et les applications OpenFiat elles-mêmes utiliseront le vôtre au même titre que tous les autres.

Deux choses à savoir avant. Servir le public signifie du trafic réel, alors dimensionnez la machine en conséquence et surveillez l’endpoint de métriques. Et un nœud public est un engagement public — les gens vont bâtir contre l’URL que vous publiez, alors retirez-la délibérément plutôt qu’en silence.

Installation

Compiler depuis les sources — pour la production, aujourd’hui

Aucune version n’a encore été taguée, c’est donc pour l’instant la seule façon d’obtenir le binaire du nœud. Il faut le toolchain Rust et un toolchain C pour RocksDB. Compilez, placez dans /usr/local/bin et faites tourner sous systemd — c’est le déploiement que cette page documente, et celui à utiliser pour un nœud dont d’autres dépendent.

shell
# Rust toolchain, then build the node binary
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
apt install -y build-essential pkg-config libssl-dev clang cmake

git clone https://github.com/OpenFiat-org/openfiat-core.git
cd openfiat-core
cargo build --release --bin openfiat-node

install -m 0755 target/release/openfiat-node /usr/local/bin/

Binaire pré-compilé — dès qu’une version est taguée

Pousser un tag v* déclenche le workflow de release, qui compile openfiat-node sur des runners natifs et publie des archives linux-x86_64 et windows-x86_64 dans les GitHub Releases. Rien n’a encore été tagué, donc cette page est vide pour l’instant. Notez que ce sont des builds de release ordinaires, ni statiques ni signés — vérifiez ce que vous téléchargez contre le workflow qui l’a produit.

Releases GitHub
shell
useradd --system --create-home --home-dir /var/lib/openfiat --shell /usr/sbin/nologin openfiat
install -m 755 openfiat-node /usr/local/bin/openfiat-node
mkdir -p /etc/openfiat
chown -R openfiat:openfiat /var/lib/openfiat

systemctl daemon-reload
systemctl enable --now openfiat-node
journalctl -u openfiat-node -f

Docker — pour les tests uniquement

Utilisez l’image pour expérimenter un nœud localement ou monter un cluster multi-nœuds jetable — pas pour faire tourner un nœud dont le réseau dépend. Elle existe pour des tests locaux reproductibles ; la production fait tourner le binaire sous systemd.

compose.yaml
# /opt/openfiat/compose.yaml
# TESTING ONLY. Use this to try a node locally or to bring up a throwaway
# cluster — run a production node from the binary under systemd instead
# (see the unit file further down this page).
services:
  node:
    image: ghcr.io/openfiat-org/openfiat-node:latest
    restart: unless-stopped
    # QUIC needs UDP; the same TCP port serves JSON-RPC, WebSocket, REST,
    # health, and metrics together — there is no separate metrics port.
    ports:
      - "4001:4001/udp"
      - "7080:7080/tcp"
    volumes:
      - /var/lib/openfiat:/data
      - /etc/openfiat/wallet.json:/data/wallet.json:ro
    command:
      - --ledger=/data
      - --identity=/data/wallet.json
      - --rpc-bind-address=0.0.0.0:7080
      - --gossip-bind-address=/ip4/0.0.0.0/udp/4001/quic-v1
      # Static multiaddr — DNS bootstrap does not resolve (see this
      # file's own top comment). Repeat the flag for several.
      - --entrypoint=/ip4/84.32.223.111/udp/4001/quic-v1/p2p/12D3KooWK9hQ7TwbfvFiaAxUbRFCkdhS7iEpAJDnewNL1anyREQ1
      # Omit to stay GossipOnly, the safe default. Any value opts into
      # real Solana devnet connectivity (OFS-4300 §4).
      - --solana-rpc-url=https://api.devnet.solana.com
    stop_grace_period: 60s
    ulimits:
      nofile: 65536
shell
install -d -m 0750 /var/lib/openfiat
docker compose -f /opt/openfiat/compose.yaml up -d
docker compose -f /opt/openfiat/compose.yaml logs -f node

Ports

  • 4001/UDPTrafic entre pairs. QUIC est le transport principal, donc ce port UDP doit être atteignable — celui que les gens oublient le plus d’ouvrir.Doit être atteignable
  • 7080/TCPJSON-RPC, WebSocket, REST, santé et métriques — un seul port réel sert tout, il n’y a pas de port distinct par surface.Doit être atteignable
  • 7080/TCPLe même port que l’API ci-dessus (GET /metrics). Restreignez-le par pare-feu à loopback/un réseau privé si vous ne voulez pas qu’il soit public.Gardez-le privé

Mettre un nœud en ligne

Suivez ces étapes dans l’ordre. Chaque étape ci-dessous apporte la commande dont elle a besoin.

  1. 01

    Préparez la machine

    Un serveur Debian ou Ubuntu à jour, un pare-feu et une horloge précise. L’horloge importe plus qu’il n’y paraît : les enregistrements portent des timestamps et des heures d’expiration, et une horloge dérivée fait rejeter par un nœud des données valides.

    shell
    # Debian 12 / Ubuntu 24.04, as root
    apt update && apt install -y ca-certificates curl gnupg ufw chrony
    
    # Clock drift breaks signature and expiry checks — keep NTP running.
    systemctl enable --now chrony
  2. 02

    Installez le nœud

    Compilez depuis les sources et faites tourner le résultat sous systemd — aucune version n’a encore été taguée, c’est donc la seule façon d’obtenir un binaire aujourd’hui, et le reste de ce manuel le suppose. Ne recourez à Docker que pour tester localement ou monter un cluster jetable.

  3. 03

    Générez le portefeuille du nœud

    Il n’y a pas de format « d’identité de nœud » distinct — l’identité d’un nœud est un vrai wallet.json de la CLI Solana, le même fichier que produit solana-keygen. Sa seed est réutilisée à la fois pour l’identité de gossip/pair du nœud et pour la clé de signature Solana. Gardez le fichier — si vous le perdez, le nœud rejoint en inconnu et recommence à bâtir sa réputation de zéro.

    shell
    # The node's identity IS a Solana CLI-format wallet.json — the same
    # file "solana-keygen new" produces (its own seed is reused for the
    # node's gossip/P2P keypair too, see crates/cli's load_or_generate_wallet).
    # There is no separate "node identity" format or command.
    solana-keygen new --outfile /etc/openfiat/wallet.json
    chmod 600 /etc/openfiat/wallet.json
    solana-keygen pubkey /etc/openfiat/wallet.json
  4. 04

    Définissez l’environnement

    openfiat-node n’a pas de fichier de configuration propre — chaque réglage est une variable d’environnement, lue une fois au démarrage : où vivent les données, sur quelle adresse écouter, quels pairs composer au démarrage et (en option) quel endpoint RPC Solana utiliser. Les pairs de bootstrap doivent être un multiaddr/IP statique, pas un nom d’hôte — le bootstrap par DNS ne résout pas.

    shell
    # There is no config file and no environment variables. Every
    # setting is a flag on the systemd unit's ExecStart below, so
    # "systemctl cat openfiat-node" shows exactly what a running node was
    # given, and "openfiat-node --help" is the whole surface.
    #
    # Try it in the foreground first — the node prints the addresses it is
    # reachable at and whether it reached Solana:
    
    openfiat-node \
      --ledger /var/lib/openfiat \
      --identity /etc/openfiat/wallet.json \
      --rpc-bind-address 0.0.0.0:7080 \
      --gossip-bind-address /ip4/0.0.0.0/udp/4001/quic-v1 \
      --entrypoint /ip4/84.32.223.111/udp/4001/quic-v1/p2p/12D3KooWK9hQ7TwbfvFiaAxUbRFCkdhS7iEpAJDnewNL1anyREQ1 \
      --solana-rpc-url https://api.devnet.solana.com
    
    # Omit --solana-rpc-url to stay GossipOnly, the safe default: the node
    # still serves the marketplace, but its on-chain answers come
    # second-hand from peers. Never put a real endpoint or API key anywhere
    # version controlled — it belongs in the unit file on the server.
    #
    # Add --ipfs-api-url http://127.0.0.1:5001 to pin protocol content and
    # earn the full reward share, and --retention archival to keep the whole
    # history instead of a rolling 30 days.
  5. 05

    Ouvrez les bons ports

    Les pairs atteignent le nœud par UDP parce que QUIC est le transport principal — c’est le port que les gens oublient le plus. Un port TCP sert JSON-RPC, WebSocket, REST, santé et métriques ensemble ; gardez-le privé si vous ne voulez pas servir de clients publiquement.

    shell
    ufw default deny incoming
    ufw allow 22/tcp                 # keep your own access
    ufw allow 4001/udp               # libp2p, QUIC — the port people most often forget
    ufw allow 443/tcp                # once nginx terminates TLS in front (see below)
    ufw allow 7080/tcp               # only if the node is exposed directly, without a proxy
    ufw enable && ufw status verbose
  6. 06

    Servez le réseau : rendez votre nœud atteignable

    C’est l’étape qui transforme un nœud, d’une chose qui observe le réseau en une chose qui le porte. Placez nginx devant et obtenez un certificat, puis indiquez au nœud son URL publique avec --public-rpc-url et il s’annonce pour que portefeuilles, explorateurs et l’app web OpenFiat elle-même puissent l’utiliser. L’ordre compte : nginx sur HTTP simple d’abord, puis certbot ajoute TLS — une configuration qui nomme déjà un certificat ne peut pas démarrer, si bien que certbot échoue avant de pouvoir émettre celui qui aurait résolu le problème. Un certificat n’est pas un ornement optionnel : une page servie en HTTPS ne peut pas ouvrir de connexion HTTP simple, donc un nœud sans certificat est invisible pour tout navigateur, aussi sain soit-il.

    /etc/nginx/sites-available/openfiat-node
    # /etc/nginx/sites-available/openfiat-node
    #
    # HTTP only at this stage, with NO TLS directives. certbot --nginx works
    # by running "nginx -t" and editing this file, so a config that already
    # points at a certificate cannot load, nginx will not start, and certbot
    # fails before it can issue the certificate that would have fixed it.
    server {
        listen 80;
        listen [::]:80;
        server_name openfiat.example.com;
    
        location / {
            proxy_pass http://127.0.0.1:7080;
            proxy_http_version 1.1;
    
            # The node serves its WebSocket event stream on the same port;
            # without these the stream downgrades to a plain request and
            # subscriptions silently never deliver.
            proxy_set_header Upgrade    $http_upgrade;
            proxy_set_header Connection "upgrade";
    
            proxy_set_header Host              $host;
            proxy_set_header X-Real-IP         $remote_addr;
            proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
    
            # Do NOT add CORS headers here — the node already sets them, and
            # two Access-Control-Allow-Origin headers on one response make
            # browsers reject it while curl sees a clean 200.
            proxy_read_timeout 300s;
        }
    }
    shell
    # The A record must already resolve for the world — certbot proves
    # control of the name over port 80. Check a public resolver, not your
    # own machine, whose cache can be stale:
    dig +short @8.8.8.8 openfiat.example.com
    
    ln -s /etc/nginx/sites-available/openfiat-node /etc/nginx/sites-enabled/
    nginx -t && systemctl reload nginx
    curl -s http://openfiat.example.com/health    # ok, before any certificate
    
    apt install -y certbot python3-certbot-nginx
    certbot --nginx -d openfiat.example.com
    
    # certbot edits the server block in place: it adds listen 443 ssl, the
    # certificate paths, and a redirect from :80. The location block and its
    # proxy headers carry over. Renewal installs itself as a systemd timer.
    # Do not hand-write a 443 block afterwards — certbot manages that one.
    
    # Then tell the network this node can be reached directly:
    #   openfiat-node --public-rpc-url https://openfiat.example.com
  7. 07

    Faites-en un service

    Sous systemd, le nœud redémarre après un plantage ou un reboot, et bénéficie d’un délai d’arrêt assez long pour que la base de données se vide proprement au lieu d’être tuée au milieu d’une écriture.

    openfiat-node.service
    # /etc/systemd/system/openfiat-node.service
    [Unit]
    Description=OpenFiat node
    Documentation=https://docs.openfiat.network
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    User=openfiat
    Group=openfiat
    ExecStart=/usr/local/bin/openfiat-node \
        --ledger /var/lib/openfiat \
        --identity /etc/openfiat/wallet.json \
        --rpc-bind-address 0.0.0.0:7080 \
        --gossip-bind-address /ip4/0.0.0.0/udp/4001/quic-v1 \
        --entrypoint /ip4/84.32.223.111/udp/4001/quic-v1/p2p/12D3KooWK9hQ7TwbfvFiaAxUbRFCkdhS7iEpAJDnewNL1anyREQ1 \
        --solana-rpc-url https://api.devnet.solana.com
    WorkingDirectory=/var/lib/openfiat
    Restart=on-failure
    RestartSec=5s
    
    # openfiat-node handles SIGTERM itself (graceful shutdown) rather than
    # needing systemd to force-kill it; this gives that shutdown path a
    # reasonable window before systemd escalates to SIGKILL.
    TimeoutStopSec=30s
    
    NoNewPrivileges=true
    ProtectSystem=strict
    ProtectHome=true
    ReadWritePaths=/var/lib/openfiat
    PrivateTmp=true
    
    # AF_NETLINK is required, not optional: binding a wildcard address makes
    # libp2p enumerate this host's interfaces, and that goes over a netlink
    # socket. Without it the QUIC listener fails and the gossip actor panics
    # while the HTTP thread survives — so systemd reports the unit active
    # and the node looks healthy while serving nothing.
    RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
    
    [Install]
    WantedBy=multi-user.target
    shell
    useradd --system --create-home --home-dir /var/lib/openfiat --shell /usr/sbin/nologin openfiat
    install -m 755 openfiat-node /usr/local/bin/openfiat-node
    mkdir -p /etc/openfiat
    chown -R openfiat:openfiat /var/lib/openfiat
    
    systemctl daemon-reload
    systemctl enable --now openfiat-node
    journalctl -u openfiat-node -f
  8. 08

    Laissez-le rattraper

    Au lieu de rejouer tout l’historique, un nouveau nœud peut découvrir et importer un snapshot annoncé par un pair de l’état actuel du marché (OFS-1300) — de vraies méthodes JSON-RPC, pas un outil séparé : getLatestSnapshot, getCheckpointHeight. Signature, version du protocole et racine d’état doivent toutes correspondre avant qu’on ne s’y fie.

    shell
    # Snapshot sync (OFS-1300) is real JSON-RPC, not a separate CLI —
    # a new node discovers and imports a peer-announced snapshot instead of
    # replaying all history:
    curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \
      -d '{"jsonrpc":"2.0","id":1,"method":"getLatestSnapshot","params":{}}'
    curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \
      -d '{"jsonrpc":"2.0","id":1,"method":"getCheckpointHeight","params":{}}'
  9. 09

    Vérifiez qu’il est sain

    GET /health confirme que le processus tourne ; getChainStatus par JSON-RPC dit s’il est GossipOnly ou RpcConnected, et son blockhash courant s’il est le dernier.

    shell
    # Is it up, and which mode is it in?
    curl -s http://localhost:7080/health
    # ok
    
    curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \
      -d '{"jsonrpc":"2.0","id":1,"method":"getChainStatus","params":{}}'
    # {"jsonrpc":"2.0","id":1,"result":{"mode":"GossipOnly","blockhash":null,"slot":null,"age_ms":null}}
    # ("RpcConnected" with a real blockhash once --solana-rpc-url is set)
    
    # The addresses your node is reachable at are in its own log — give one
    # of these to another operator as their --entrypoint:
    journalctl -u openfiat-node | grep "reachable at a new address"
  10. 10

    Il fait déjà partie du réseau

    Il n’y a pas d’étape « annoncer » distincte — dès qu’un nœud a des pairs de bootstrap, il propage par gossip et est propagé automatiquement ; personne ne l’approuve. Mettre en stake, publier des métadonnées dans le registre de services, adhérer à des litiges et émettre des votes de gouvernance sont des actions distinctes, guidées par portefeuille, qu’un client réalise contre le nœud en cours d’exécution — voir le guide de participation correspondant à chacune.

    Un nœud met OPEN en stake pour devenir un participant actif. Mais le stake n’achète pas de réputation : un opérateur peu performant ne peut pas se rattraper en misant davantage. La priorité effective combine réputation, stake et performance réseau mesurée.

  11. 11

    Surveillez-le

    Les signaux qui prédisent vraiment les ennuis sont les pairs connectés, le mode de la chaîne (GossipOnly vs RpcConnected) et l’âge du blockhash. Alertez sur ceux-là et vous saurez avant vos utilisateurs.

    prometheus.yml
    # /etc/prometheus/prometheus.yml — same port as everything else,
    # no separate metrics listener to configure on the node's own side.
    scrape_configs:
      - job_name: openfiat-node
        static_configs:
          - targets: ["127.0.0.1:7080"]
  12. 12

    Gardez-le à jour

    Arrêtez, remplacez le binaire, démarrez. Les nœuds se mettent à jour un par un, donc le réseau n’a jamais besoin d’un arrêt coordonné, et les événements de gossip manqués sont rejoués au démarrage.

    shell
    systemctl stop openfiat-node        # SIGTERM, lets RocksDB flush
    # docker: docker compose pull node && docker compose up -d node
    install -m 0755 ./openfiat-node /usr/local/bin/
    systemctl start openfiat-node
    
    # Missed gossip events replay automatically on start.
    journalctl -u openfiat-node -f
  13. 13

    Sauvegardez ce qui ne peut pas être régénéré

    L’état du marché peut toujours être resynchronisé depuis un snapshot. Le portefeuille ne peut pas être régénéré. Les soldes et la garde vivent sur Solana, pas sur votre disque.

    shell
    # Back up what cannot be re-derived. Marketplace state can always be
    # re-synced from a snapshot; the wallet cannot be regenerated.
    tar czf openfiat-wallet-$(date +%F).tar.gz /etc/openfiat/wallet.json
    
    # Authoritative financial state lives on Solana, not on the node's own
    # RocksDB volume.

Quand quelque chose ne va pas

Aucun pair ne se connecte

L’UDP 4001 est bloqué, ou --entrypoint pointe vers une adresse que les pairs ne peuvent pas réellement atteindre — ce doit être un multiaddr/IP statique, pas un nom d’hôte (le bootstrap par DNS ne résout pas). Votre propre nœud journalise les adresses où il est atteignable dès qu’il écoute.

shell
ss -lunp | grep 4001 && journalctl -u openfiat-node -n 100

La synchronisation ne se termine jamais

L’import de snapshot (OFS-1300) n’a pas fini, ou aucun pair n’a encore annoncé un snapshot assez récent — vérifiez getLatestSnapshot/getCheckpointHeight.

shell
journalctl -u openfiat-node -n 200 --no-pager | grep -i snapshot

L’usage du disque ne cesse de croître

RocksDB n’a pas compacté.

shell
du -sh /var/lib/openfiat/*

Signatures ou expirations rejetées

Dérive de l’horloge. Les enregistrements portent des timestamps et une expiration, l’horloge de l’hôte doit donc être correcte.

shell
chronyc tracking

Ce qu’un nœud doit exposer

C’est tout ce que le nœud exporte aujourd’hui — le nombre de pairs, le mode de la chaîne et la progression de synchronisation ne sont pas encore des métriques Prometheus, seulement des valeurs que vous pouvez interroger par JSON-RPC (getChainStatus, getLatestSnapshot, getCheckpointHeight).

Infrastructure

CPU · Mémoire · Disque · Débit réseau

Protocole (GET /metrics)

rpc_requests_total · rpc_errors_total

Héberger l’interface utilisateur

OpenFiat sépare le protocole de ses interfaces. N’importe qui peut héberger une interface web, une passerelle mobile, un portail d’entreprise ou un marché régional, et chacun atteint le même marché.

Quelle que soit l’interface utilisée, chaque participant interagit avec le même marché décentralisé.

Interface web officielle · Interfaces de la communauté · Interfaces de commerçant · Marchés régionaux · Portails d’entreprise

Ce à quoi une interface se connecte

Les interfaces ne parlent pas directement à la chaîne. Elles se connectent à un ou plusieurs nœuds OpenFiat proches, et basculent vers un autre nœud si l’un devient indisponible.

Surface d’API du nœud

  • MarchéRécupérer des annonces · Créer des annonces · Mettre à jour des annonces · Retirer des annonces
  • ÉchangeRéserver des annonces · Synchroniser les sessions d’échange · Envoyer des confirmations de paiement
  • InfrastructureDécouverte de pairs · Découverte de passerelles · Informations de snapshot · Intelligence des risques
  • GouvernanceDécouverte des propositions · Envoi de votes · Informations de trésorerie

Chaque nœud conforme expose la même surface d’API, si bien qu’une interface écrite contre un nœud fonctionne contre tous.

Les nœuds ne prennent jamais en garde les fonds des utilisateurs. Toutes les opérations financières restent sous le contrôle des contrats intelligents Solana.