A high-performance Ethereum node proxy built in Rust that monitors node health and automatically routes traffic to healthy endpoints.
Vixy is a transparent proxy that sits between your application and Ethereum nodes (both Execution Layer and Consensus Layer). It continuously monitors node health, tracks synchronization status, and intelligently routes requests to healthy nodes with automatic failover.
Key Capabilities:
- Health Monitoring: Continuous health checks for EL and CL nodes
- Automatic Failover: Seamless routing to backup nodes when primary nodes fail
- WebSocket Support: Proxies WebSocket connections with subscription replay on reconnection
- Metrics & Observability: Comprehensive Prometheus metrics and Grafana dashboards
- HTTP & WebSocket Proxying: Support for both REST APIs and WebSocket subscriptions
# Pull the latest image
docker pull ghcr.io/chainbound/vixy:latest
# Create a configuration file
cp config.example.toml config.toml
# Edit config.toml with your node URLs
# Run Vixy
docker run -v $(pwd)/config.toml:/app/config.toml \
-p 8080:8080 -p 9090:9090 \
ghcr.io/chainbound/vixy:latest# Clone the repository
git clone https://github.com/chainbound/vixy.git
cd vixy
# Build and run
cargo run --release -- --config config.tomlCreate a config.toml file based on config.example.toml:
[server]
listen = "127.0.0.1:8080"
[metrics]
enabled = true
listen = "127.0.0.1:9090"
[[el_nodes]]
name = "geth-primary"
url = "http://geth-1:8545"
ws_url = "ws://geth-1:8546"
tier = "primary"
[[cl_nodes]]
name = "lighthouse-1"
url = "http://lighthouse-1:5052"See config.example.toml for all available options.
Vixy exposes the following HTTP endpoints:
POST /el
- Proxies JSON-RPC requests to healthy EL nodes (uses JSON-RPC protocol, not REST)
- Selects first healthy primary node
- Falls back to first healthy backup node if all primary nodes are unhealthy
- Automatic failover: primary → backup tier when no primary nodes available
- Supports batch requests
- Content-Type:
application/json
Example:
curl -X POST http://localhost:8080/el \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}'GET /el/ws
- Transparent WebSocket proxy supporting all JSON-RPC methods over WebSocket
- Connects to first healthy primary node, falls back to first healthy backup
- Special handling for
eth_subscribeandeth_unsubscribe:- Tracks active subscriptions
- Automatic subscription replay on reconnection
- Health-aware upstream switching (primary → backup tier when needed)
- Supports both text and binary WebSocket frames
Example:
const ws = new WebSocket('ws://localhost:8080/el/ws');
// Subscribe to new blocks
ws.send(JSON.stringify({
jsonrpc: '2.0',
method: 'eth_subscribe',
params: ['newHeads'],
id: 1
}));
// Can also send regular JSON-RPC calls over WebSocket
ws.send(JSON.stringify({
jsonrpc: '2.0',
method: 'eth_blockNumber',
params: [],
id: 2
}));ANY /cl/{path}
- Proxies all HTTP methods (GET, POST, etc.) to healthy CL nodes (uses REST API)
- Selects first healthy CL node from configured nodes
- Forwards all paths under
/cl/to beacon node API endpoints - Automatic failover to next healthy node if current node becomes unhealthy
Example:
# Get beacon chain head
curl http://localhost:8080/cl/eth/v1/beacon/headers/head
# Check node health
curl http://localhost:8080/cl/eth/v1/node/health
# Get node syncing status
curl http://localhost:8080/cl/eth/v1/node/syncingGET /health
- Simple health check for the proxy itself
- Returns:
OK(200 status) - Useful for load balancer health checks
Example:
curl http://localhost:8080/healthGET /status
- Detailed JSON status of all monitored nodes
- Shows health state, block/slot numbers, and lag
- Content-Type:
application/json
Example:
curl http://localhost:8080/status | jq .Response format:
{
"el_chain_head": 12345678,
"cl_chain_head": 9876543,
"el_failover_active": false,
"el_nodes": [
{
"name": "geth-primary",
"http_url": "http://geth-1:8545",
"is_primary": true,
"block_number": 12345678,
"lag": 0,
"check_ok": true,
"is_healthy": true
}
],
"cl_nodes": [
{
"name": "lighthouse-1",
"url": "http://lighthouse-1:5052",
"slot": 9876543,
"lag": 1,
"health_ok": true,
"is_healthy": true
}
]
}GET /metrics
- Prometheus metrics endpoint
- Only available if
metrics.enabled = truein config - Can be on main port or separate port (see
metrics.port)
Example:
curl http://localhost:9090/metricsSee grafana/README.md for full metrics documentation.
- Configuration Guide - Complete configuration reference
- Monitoring with Grafana - Setup Grafana dashboards
- Integration Testing - Running integration tests with Kurtosis
- Agent Design - Implementation details and architecture
- Development Diary - Development log and design decisions
- Blog Post - Deep dive into Vixy's features
- API docs available at: https://docs.rs/vixy (coming soon)
- Metrics reference: grafana/README.md
- Rust 1.86 or later (for
let_chainssupport) - Docker (for integration tests)
- Kurtosis (for testnet setup)
- just (optional, for task automation)
# Format code
cargo fmt
# Run lints
cargo clippy -- -D warnings
# Run unit tests
cargo test
# Run BDD tests
cargo test --test cucumber
# Full CI check
just ciVixy includes comprehensive integration tests:
# Run full integration test suite (Kurtosis + WSS tests)
just integration-test
# Or step-by-step for Kurtosis tests
just kurtosis-up # Start testnet
just kurtosis-vixy # Run Vixy
just kurtosis-test # Run tests
just kurtosis-down # Cleanup
# Or run WSS tests separately
just test-wssThe integration-test command runs:
- Kurtosis Tests: Against a local Ethereum testnet
- WSS Tests: Against public Hoodi endpoints (non-critical, may fail)
Note: WSS tests use public Hoodi endpoints (publicnode.com, no API key required) and failures are non-critical. They verify TLS/WSS support but may fail due to network issues, rate limiting, or endpoint unavailability.
See INTEGRATION_TESTS.md for detailed testing documentation.
Vixy exposes Prometheus metrics on /metrics (default port 9090). A pre-configured Grafana dashboard is available in the grafana/ directory.
Dashboard Features:
- EL/CL node health and lag monitoring
- Request rates and latency (P50/P95/P99)
- WebSocket connection tracking
- Failover events and status
See grafana/README.md for setup instructions.
We welcome contributions! Here's how to get started:
- Bug Reports: Use the issue tracker with a clear description and reproduction steps
- Feature Requests: Open an issue describing the use case and proposed solution
- Security Issues: Please report security vulnerabilities privately to [email protected]
-
Fork the repository and create a feature branch
git checkout -b feat/your-feature-name
-
Make your changes following our coding standards:
- Run
cargo fmtbefore committing - Ensure
cargo clippy -- -D warningspasses - Add tests for new functionality
- Update documentation as needed
- Run
-
Test thoroughly:
# Run full test suite just ci # Run integration tests just integration-test
-
Commit with clear messages:
git commit -m "feat: add support for node prioritization"Follow Conventional Commits format:
feat:- New featuresfix:- Bug fixesdocs:- Documentation changesrefactor:- Code refactoringtest:- Test additions/changeschore:- Maintenance tasks
-
Submit a Pull Request:
- Provide a clear description of the changes
- Reference any related issues
- Ensure CI passes
- All submissions require review before merging
- Maintainers will provide feedback within a few days
- Address review comments and update your PR
- Once approved, a maintainer will merge your PR
We use these tools to maintain code quality:
- rustfmt: Code formatting (
cargo fmt) - clippy: Linting (
cargo clippy) - cucumber: BDD testing (
cargo test --test cucumber) - just: Task automation (
just --list)
Run the full CI suite locally before submitting:
just ci- Discord: Join our community (coming soon)
- Discussions: Use GitHub Discussions
- Documentation: Check AGENT.md for architecture details
Future enhancements we're considering:
- Dynamic node discovery and registration
- Advanced load balancing strategies
- Rate limiting per application/API key
- gRPC support for CL nodes
- WebAssembly plugin system
- Multi-region node distribution
Have ideas? Open an issue or discussion!
This project is licensed under the MIT License - see the LICENSE file for details.
Vixy depends on various open-source libraries. Their licenses can be found in their respective repositories:
- prometric - MIT/Apache-2.0
- tokio - MIT License
- axum - MIT License
- reqwest - MIT/Apache-2.0
- prometheus - Apache-2.0
Built with ❤️ by Chainbound
Special thanks to:
- The Ethereum community for the robust infrastructure
- All contributors who have helped improve Vixy
- The Rust community for excellent tooling and libraries
Need Help? Check our documentation or open an issue.