fleet-router
A reverse proxy and load balancer for the Antelope SHiP (State History Plugin) WebSocket protocol.
Homepage · Configuration · Operations · Observability · 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 the session moves to another node, resumes at the next block, drops replayed blocks, and replays client frames sent during the swap.
- Range-aware, least-connections routing. Requests go to an upstream whose trace range covers the requested block, otherwise to the least-loaded healthy one. Optional per-node
priorityandweightmark preferred and last-resort nodes and split load.fetch_finality_datarequests go only to nodes whose finality range covers the block. - Stale nodes are deprioritized, not excluded. Upstreams that stop advancing drop down the list.
- 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.
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, upstream TLS, and multi-network
listeners. - Running in production: security, running as a service (systemd, Docker, launchd, Windows), graceful shutdown, corrupted SHiP logs, and tuning.
- Observability: logging, health and readiness endpoints, and the Prometheus metrics.
- Dashboard and control API: the opt-in live dashboard, status page, JSON API, and token-protected control actions.
- 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. 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.