Saltar al contenido

Ejecutar un nodo OpenFiat

Los operadores de nodos mantienen el mercado descentralizado que se sitúa por encima de la cadena de bloques. Los validadores de Solana aseguran la cadena y ejecutan los programas de OpenFiat; los nodos llevan los anuncios, la reputación, la mensajería y el descubrimiento.

Los comandos siguientes usan el despliegue de referencia: el servicio openfiat-node, /etc/openfiat para la configuración y /var/lib/openfiat para los datos.

Hardware

Mínimo

4 núcleos de CPU · 16 GB de RAM · SSD NVMe de 250 GB · Conexión de banda ancha estable

Recomendado para producción

8–16 núcleos de CPU · 32 GB de RAM o más · SSD NVMe de 1 TB · Red de alto ancho de banda y baja latencia · Protección eléctrica con SAI (UPS) · Conectividad a internet redundante

El nodo es un único binario de Rust. libp2p (QUIC, Noise, Yamux) y RocksDB están compilados dentro: no hay nada que instalar por separado.

Dónde ejecutarlo

AllenHark lidera el desarrollo inicial del protocolo y vende las dos cosas que un nodo necesita: un servidor y acceso RPC a Solana. Los operadores de nodos obtienen un 50% de descuento en ambos, como parte del programa OpenFiat.

Alojamiento de servidores

Almacenamiento NVMe en enlaces de 10 Gbps, en Fráncfort, Ámsterdam y Chicago. Dimensiónalo según el hardware anterior: el almacenamiento es lo que un nodo completo va necesitando, así que di qué vas a ejecutar y se puede especificar por ti.

Ver precios

RPC y gRPC de Solana

Conexiones con stake, de modo que las transacciones que tu nodo envía no quedan en cola tras las de todos los demás. El acceso se concede por lista de IP permitidas en lugar de una clave de API. Yellowstone gRPC está disponible para transmitir actualizaciones de cuentas y slots.

Ver precios

Reclamar el descuento

No hay código que introducir. Pregunta en Discord o en el chat de allenhark.com, di que ejecutas un nodo OpenFiat, y el descuento se aplica a tu pedido.

Sirve a la red, no solo a ti

Un nodo que solo lee es un invitado. Un nodo al que el público puede llegar es infraestructura: las billeteras, exploradores y aplicaciones web tienen que hablar con *alguien*, y hoy existen demasiado pocos de esos alguien. Cada operador que pone su nodo tras TLS y configura --public-rpc-url amplía ese conjunto, que es la diferencia entre una red con varias puertas de entrada independientes y una con un único punto de fallo del que todos dependen en silencio. Cuesta un certificado y un proxy inverso. También se recompensa: un nodo alcanzable es uno que los pares pueden desafiar y recompensar, y las propias aplicaciones de OpenFiat usarán el tuyo junto a todos los demás.

Dos cosas que conviene saber antes de hacerlo. Servir al público significa tráfico real, así que dimensiona la máquina para ello y vigila el endpoint de métricas. Y un nodo público es un compromiso público: la gente construirá contra la URL que publiques, así que retírala de forma deliberada en lugar de silenciosa.

Instalación

Compilar desde el código fuente: para producción, hoy

Aún no se ha etiquetado ninguna versión, así que esta es actualmente la única forma de obtener un binario del nodo. Necesita el toolchain de Rust y un toolchain de C para RocksDB. Compílalo, colócalo en /usr/local/bin y ejecútalo bajo systemd: ese es el despliegue que documenta esta página, y el que usar para un nodo del que otros dependen.

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/

Binario precompilado: una vez que se etiquete una versión

Empujar una etiqueta v* ejecuta el flujo de release, que compila openfiat-node en runners nativos y publica archivos linux-x86_64 y windows-x86_64 en GitHub Releases. Aún no hay nada etiquetado, así que esa página está actualmente vacía. Ten en cuenta que son builds de release ordinarios, no estáticos ni firmados: verifica lo que descargues contra el flujo que lo produjo.

Releases de 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: solo para pruebas

Usa la imagen para probar un nodo localmente o para levantar un clúster multinodo desechable, no para ejecutar un nodo del que dependa la red. Existe para pruebas locales reproducibles; producción ejecuta el binario bajo 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

Puertos

  • 4001/UDPTráfico entre pares. QUIC es el transporte principal, así que este puerto UDP debe ser alcanzable: el que la gente olvida abrir con más frecuencia.Debe ser alcanzable
  • 7080/TCPJSON-RPC, WebSocket, REST, salud y métricas: un solo puerto real sirve todo ello, no hay un puerto separado por superficie.Debe ser alcanzable
  • 7080/TCPEl mismo puerto que la API anterior (GET /metrics). Restríngelo con firewall a loopback o a una red privada si no quieres que sea público.Mantener privado

Poner un nodo en línea

Sigue estos pasos en orden. Cada paso incluye el comando que necesita.

  1. 01

    Prepara la máquina

    Un servidor Debian o Ubuntu actual, un firewall y un reloj preciso. El reloj importa más de lo que parece: los registros llevan marcas de tiempo y tiempos de caducidad, y un reloj desfasado hace que un nodo rechace datos válidos.

    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

    Instala el nodo

    Compila desde el código fuente y ejecuta el resultado bajo systemd: aún no se ha etiquetado ninguna versión, así que esa es la única forma de obtener un binario hoy, y el resto de este manual lo asume. Recurre a Docker solo cuando pruebes localmente o levantes un clúster desechable.

  3. 03

    Genera la billetera del nodo

    No hay un formato de "identidad de nodo" separado: la identidad de un nodo es un wallet.json real de la CLI de Solana, el mismo archivo que produce solana-keygen. Su semilla se reutiliza tanto para la identidad de gossip/par del nodo como para su clave de firma de Solana. Conserva el archivo: si lo pierdes, el nodo se reincorpora como un desconocido y empieza a construir reputación de nuevo desde cero.

    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

    Configura el entorno

    openfiat-node no tiene un archivo de configuración propio: cada ajuste es una variable de entorno, leída una vez al arrancar: dónde viven los datos, en qué dirección escuchar, a qué pares marcar al inicio y (opcionalmente) qué endpoint RPC de Solana usar. Los pares de arranque deben ser un multiaddr/IP estático, no un nombre de host: el bootstrap por DNS no se resuelve.

    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

    Abre los puertos correctos

    Los pares alcanzan el nodo por UDP porque QUIC es el transporte principal: ese es el puerto que la gente olvida con más frecuencia. Un puerto TCP sirve JSON-RPC, WebSocket, REST, salud y métricas juntos; mantenlo privado si no quieres servir clientes públicamente.

    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

    Sirve a la red: haz tu nodo alcanzable

    Este es el paso que convierte un nodo de algo que observa la red en algo que la lleva. Pon nginx delante y obtén un certificado, luego dile al nodo su URL pública con --public-rpc-url y se anuncia para que billeteras, exploradores y la propia app web de OpenFiat puedan usarlo. El orden importa: nginx sobre HTTP simple primero, luego certbot añade TLS: una configuración que ya nombra un certificado no puede arrancar, así que certbot falla antes de poder emitir el que lo habría arreglado. Un certificado no es un adorno opcional: una página servida por HTTPS no puede abrir una conexión HTTP simple, así que un nodo sin él es invisible para cualquier navegador por muy sano que esté.

    /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

    Ejecútalo como servicio

    Bajo systemd el nodo se reinicia tras un fallo o reinicio, y obtiene un periodo de gracia de apagado lo bastante largo para que la base de datos se vacíe limpiamente en lugar de ser matada a media escritura.

    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

    Déjalo ponerse al día

    En lugar de reproducir todo el historial, un nodo nuevo puede descubrir e importar un snapshot anunciado por un par del estado actual del mercado (OFS-1300): métodos JSON-RPC reales, no una herramienta aparte: getLatestSnapshot, getCheckpointHeight. La firma, la versión del protocolo y la raíz de estado tienen que coincidir antes de confiar en él.

    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

    Comprueba que está sano

    GET /health confirma que el proceso está en marcha; getChainStatus por JSON-RPC te dice si es GossipOnly o RpcConnected, y su blockhash actual si es lo segundo.

    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

    Ya forma parte de la red

    No hay un paso de "anunciar" separado: una vez que un nodo tiene pares de arranque, propaga por gossip y se le propaga automáticamente; nadie lo aprueba. Hacer stake, publicar metadatos en el registro de servicios, unirse a disputas y emitir votos de gobernanza son acciones separadas impulsadas por billetera que un cliente realiza contra el nodo en marcha: consulta la guía de participación correspondiente a cada una.

    Un nodo hace stake de OPEN para convertirse en participante activo. Pero el stake no compra reputación: un operador con mal rendimiento no puede compensarlo haciendo más stake. La prioridad efectiva combina reputación, stake y el rendimiento de red medido.

  11. 11

    Vigílalo

    Las señales que realmente predicen problemas son los pares conectados, el modo de cadena (GossipOnly vs RpcConnected) y la antigüedad del blockhash. Alerta sobre esas y lo sabrás antes que tus usuarios.

    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

    Mantenlo al día

    Detén, reemplaza el binario, arranca. Los nodos se actualizan de uno en uno, así que la red nunca necesita una interrupción coordinada, y los eventos de gossip perdidos se reproducen al arrancar.

    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

    Respalda lo que no puede regenerarse

    El estado del mercado siempre puede re-sincronizarse desde un snapshot. La billetera no puede regenerarse. Los saldos y el depósito en garantía viven en Solana, no en tu disco.

    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.

Cuando algo va mal

No se conectan pares

UDP 4001 está bloqueado, o --entrypoint apunta a una dirección que los pares no pueden alcanzar realmente: debe ser un multiaddr/IP estático, no un nombre de host (el bootstrap por DNS no se resuelve). Tu propio nodo registra las direcciones en las que es alcanzable una vez que está escuchando.

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

La sincronización nunca termina

La importación del snapshot (OFS-1300) no ha terminado, o ningún par ha anunciado aún un snapshot lo bastante reciente: comprueba getLatestSnapshot/getCheckpointHeight.

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

El uso de disco sigue creciendo

RocksDB no ha compactado.

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

Firmas o caducidades rechazadas

Desfase del reloj. Los registros llevan marcas de tiempo y caducidad, así que el reloj del host tiene que ser correcto.

shell
chronyc tracking

Qué debe exponer un nodo

Eso es todo lo que el nodo exporta hoy: el número de pares, el modo de cadena y el progreso de sincronización aún no son métricas de Prometheus, solo valores que puedes consultar por JSON-RPC (getChainStatus, getLatestSnapshot, getCheckpointHeight).

Infraestructura

CPU · Memoria · Disco · Rendimiento de red

Protocolo (GET /metrics)

rpc_requests_total · rpc_errors_total

Alojar la interfaz de usuario

OpenFiat separa el protocolo de sus interfaces. Cualquiera puede alojar una interfaz web, una pasarela móvil, un portal empresarial o un mercado regional, y todas ellas llegan al mismo mercado.

Independientemente de la interfaz que se use, cada participante interactúa con el mismo mercado descentralizado.

Interfaz web oficial · Interfaces de la comunidad · Interfaces de comerciante · Mercados regionales · Portales empresariales

A qué se conecta una interfaz

Las interfaces no hablan directamente con la cadena. Se conectan a uno o más nodos OpenFiat cercanos, y conmutan a otro nodo si uno deja de estar disponible.

Superficie de API del nodo

  • MercadoBuscar anuncios · Crear anuncios · Actualizar anuncios · Eliminar anuncios
  • OperacionesReservar anuncios · Sincronizar sesiones de operación · Enviar confirmaciones de pago
  • InfraestructuraDescubrimiento de pares · Descubrimiento de pasarelas · Información de snapshots · Inteligencia de riesgo
  • GobernanzaDescubrimiento de propuestas · Envío de votos · Información de tesorería

Todo nodo conforme expone la misma superficie de API, de modo que una interfaz escrita contra un nodo funciona contra todos.

Los nodos nunca custodian fondos de los usuarios. Todas las operaciones financieras siguen bajo el control de los contratos inteligentes de Solana.