fleet-router
A reverse proxy and load balancer for the Antelope SHiP (State History Plugin) WebSocket protocol.
Homepage · Configuration · Operations · Observability · Chain API · Dashboard & API · Changelog
Run more than one SHiP node? Put fleet-router in front of them and give your clients (Hyperion, other indexers, custom consumers) one resilient endpoint instead of pinning each consumer to one node.
Clients open a single WebSocket connection to the router. The router picks a healthy upstream, forwards its ABI, and proxies the stream. If that upstream drops, the router fails over to another suitable node, resumes get_blocks at the next block, and de-duplicates blocks the client already has. The client connection stays open.
+-----------------------+
| upstream SHiP node A | (active)
+-----> | ws://hostA:port |
| +-----------------------+
+--------+ WebSocket +--+-----------+
| client | ============> | fleet-router | range-aware / least-connections
+--------+ +--+-----------+ selection + health monitoring
| +-----------------------+
+-----> | upstream SHiP node B | (failover target:
on upstream A failure, | ws://hostB:port | resume at next block,
transparent swap to B ----> +-----------------------+ de-duplicate blocks)
Features
- Failover without reconnecting. On upstream loss, a silent socket or a stalled stream, the session moves to another node, resumes at the next block with the client's outstanding credit, and drops blocks the client already has.
- Range-aware, least-connections routing. Each
get_blocksgoes to an upstream that has the requested block for every log it asks for (traces, deltas, finality data), otherwise to the least-loaded healthy one. Optional per-nodepriorityandweightmark preferred and last-resort nodes and split load. - Stale and lagging nodes are deprioritized, not excluded. Upstreams that stop advancing, or fall behind the fleet head, drop down the list.
- Range-split fleets. Mark archive upstreams
"role": "frozen"and the listener presents live nodes plus frozen range servers (fixed block ranges served from archived logs, no nodeos) as one SHiP node: the router answers status itself, routes each request by block range, and hands the stream from one upstream to the next. See Range-split fleets. - Chain API (opt-in). A nodeos-compatible HTTP port per listener: block lookups go to the frozen range server or live node that holds the block,
get_infoand state calls to live nodes, push and exec are off by default. See Chain API. - Bounded failure on corrupted SHiP logs. A block that breaks every upstream ends the session with close code 1011 and a clear reason instead of a silent stall. Opt-in quarantine skips one node for just the bad block range.
- Several networks in one process. Each listener has its own port, upstream pool,
chain_id, connection cap, and/ready/<name>check. chain_idverification. Upstreams that report the wrong chain stay offline. Older nodes that omitchain_id(FIO and other EOSIO 2.0-based builds) stay usable unless you require it.- Operable. Prometheus metrics, health and readiness endpoints,
tracinglogs, graceful shutdown, upstreamwss://, and connection, timeout and message-size limits. - Live dashboard and control API (opt-in). See every upstream's block range, load and health in real time, and drain a node for maintenance: its sessions move to other nodes without the clients reconnecting.
Installation
Prebuilt archives for Linux x86_64, macOS (arm64 and x86_64) and Windows x86_64 are attached to each GitHub Release. To build from source:
Requirements and supported platforms
fleet-router builds on Linux, macOS, and Windows (x86_64 and arm64).
- Rust ≥ 1.99 (MSRV). Install it with rustup if needed.
- A C compiler and CMake on
PATH, to buildaws-lc-rsfor upstreamwss://. Not needed at runtime.
ABI handling uses the pure-Rust rs_abieos backend, so libclang is not required.
Quick start
# 2. list your SHiP nodes in config.json
To start fleet-router at boot and restart it after a crash, run it as a service: systemd, Docker, launchd or Windows.
A minimal config with two SHiP nodes:
A bare host:port is dialed as ws://; use wss://host:port for nodes that serve TLS. Then point your client's SHiP URL at the router (ws://<router-host>:17000) instead of a single node.
On startup the router validates the config and logs its upstream monitors:
configuration is valid.
INFO starting upstream monitor name="SHiP Node 1" upstream=127.0.0.1:18080
INFO listening for clients address=0.0.0.0 port=17000
Commands
fleet-router config init <path> Write a sample config file to <path>.
fleet-router config test <path> Parse and validate a config, then test upstream connectivity.
[--strict] Also exit 1 on an invalid config, a coverage hole, an
unreported archive, or archived blocks that no archive
with api_endpoint covers on a chain API listener.
fleet-router run [--config <path>] Run the proxy.
fleet-router check [--port <port>] Exit 0 if 127.0.0.1:<port> accepts TCP (default 17000).
fleet-router --version Print the version.
fleet-router --help Print help.
--config is global and defaults to ./config.json.
Documentation
- Configuration reference: every field and default, topology and stitching, the chain API, upstream TLS, and multi-network
listeners. - Running in production: routing and failover, range-split fleets with frozen range servers, security, running as a service (systemd, Docker, launchd, Windows), graceful shutdown, corrupted SHiP logs, and tuning.
- Observability: logging, health and readiness endpoints,
/coverage, the Prometheus metrics, and alerts. - Chain API: the opt-in nodeos-compatible HTTP port and how it routes requests.
- Dashboard and control API: the opt-in live dashboard, status page, JSON API, and token-protected control actions.
- Example configs:
example.config.json(two full nodes) andexample.stitched.config.json(archived ranges, live nodes and a chain API). - Deployment samples:
deploy/fleet-router.service,deploy/fleet-router@.service, anddeploy/docker-compose.multi-network.yml.
Security
The client listener is plaintext ws:// and unauthenticated, and so is the optional chain API port (plain HTTP). Run fleet-router on a trusted network or behind a TLS-terminating reverse proxy that adds access control. Do not expose it directly to the public internet. See Security for details.
To report a vulnerability, follow SECURITY.md. Please do not open public issues for security reports.
Contributing
Contributions are welcome. CONTRIBUTING.md covers the development setup, the CI checks, and the pre-PR checklist. Tests run against an in-repo mock SHiP double and need no external services. This project follows the Code of Conduct.
Release notes are in CHANGELOG.md (Keep a Changelog format).
License
Licensed under the MIT License. © EOS Rio.