Professional blockchain infrastructure & public RPC gateway β powered by rydone.xyz
A self-hosted RPC endpoint dashboard with live node metrics, real request tracking, and historical chart data. Built for validators who operate their own nodes and want a clean public-facing interface for their endpoints.
Live: endpoint.rydone.xyz Β· Stats API: stats.rydone.xyz
- Live node stats β block height, block time, peers, memory, goroutines from Prometheus
- Real request counters β total requests read from nginx access logs (no mocks)
- Live latency β pings stats API server for accurate latency per chain
- Historical charts β hourly snapshots stored server-side, visualized as area charts
- Multi-chain β one backend manages all nodes; adding a chain = one config entry
- EVM + Cosmos β supports pure Cosmos SDK and EVM-compatible chains
- Staking banner β per-chain validator staking link with explorer integration
- Daily load tester β sends 50k requests/day per chain to maintain healthy traffic stats
| Chain | Chain ID | Type |
|---|---|---|
| Axone | axone-1 |
Cosmos |
| Dungeon | dungeon-1 |
Cosmos |
| Lumen | lumen |
Cosmos |
| Regen | regen-1 |
Cosmos |
| Medas Digital | medasdigital-2 |
Cosmos |
| Chain | Chain ID | Type |
|---|---|---|
| Safrochain | safro-test-1 |
Cosmos |
| Empeiria | empe-testnet-2 |
Cosmos |
| Kiichain | oro_1336-1 |
Cosmos + EVM |
| Republic AI | raitestnet_77701-1 |
Cosmos + EVM |
| Pushchain | push_42101-1 |
Cosmos + EVM |
dashboard-endpoint/
βββ rpc-gateway/ # Frontend β React + TypeScript + Vite
β βββ public/ # Static assets
β β βββ logo.png # Site logo (used in sidebar & footer)
β β βββ axone.png # Chain logos
β β βββ dungeon.png
β β βββ lumen.png
β β βββ regen.png
β β βββ medas.png
β β βββ empeiria.png
β β βββ kiichain.png
β β βββ safrochain.jpg
β β βββ republicai.jpg
β β βββ pushchain.jpg
β β βββ website.png # Social icons
β β βββ git.svg
β β βββ twit.svg
β β βββ telegram.svg
β βββ src/
β β βββ data/
β β β βββ index.ts # β
ALL network configs live here
β β βββ components/
β β β βββ Avatar.tsx # Chain icon β shows logo or initials fallback
β β β βββ CopyButton.tsx # Copy endpoint URL to clipboard
β β β βββ CopyPeers.tsx # Copy peers list helper
β β β βββ EndpointCard.tsx # RPC / WSS / gRPC / REST / EVM tabs
β β β βββ RequestChart.tsx # Recharts area chart (real or mock data)
β β β βββ ChartTooltip.tsx # Custom chart tooltip
β β β βββ StakeBanner.tsx # Validator staking CTA banner
β β β βββ StatCard.tsx # Individual metric card
β β β βββ Footer.tsx # Site footer with network status summary
β β βββ pages/
β β β βββ Sidebar.tsx # Left sidebar β chain list, search, toggle
β β β βββ MainContent.tsx # Main dashboard area
β β βββ hooks/
β β β βββ useStore.ts # Zustand global state (active chain, tab, range)
β β β βββ useNodeStats.ts # Polls GET /api/stats/:chainId every 10s
β β β βββ useLatency.ts # Pings /health for live latency measurement
β β β βββ useLiveRps.ts # Live req/sec with simulated jitter
β β β βββ useChartData.ts # Fetches GET /api/history/:chainId
β β β βββ useCopy.ts # Clipboard utility hook
β β βββ App.tsx
β β βββ main.tsx
β β βββ index.css
β βββ index.html
β βββ vite.config.ts
β βββ tailwind.config.js
β βββ package.json
β
βββ rpc-stats-api/ # Backend β Express + TypeScript
β βββ src/
β β βββ chains.ts # β
ALL chain configs live here
β β βββ index.ts # Express server, routes, scrape scheduler
β β βββ stats.ts # Combines Prometheus + nginx log + EVM data
β β βββ prometheus.ts # Prometheus text format parser
β β βββ nginxlog.ts # Nginx access log line counter
β β βββ history.ts # Hourly snapshot storage β /var/lib/rpc-stats/
β βββ .env.example
β βββ rpc-stats-api.service # systemd unit (optional)
β βββ package.json
β
βββ README.md
In config/app.toml for each node:
[telemetry]
enabled = true
prometheus-retention-time = 60In config/config.toml:
[instrumentation]
prometheus = true
prometheus_listen_addr = ":10660" # unique port per nodeRestart node and verify:
curl http://localhost:10660/metrics | grep tendermint_consensus_heightEdit rpc-stats-api/src/chains.ts:
export const CHAINS: ChainConfig[] = [
{
chainId: 'axone-1',
name: 'Axone',
metricsPort: 10660, // Prometheus metrics port
restPort: 10317, // REST API port
rpcPort: 10657, // Tendermint RPC port
testnet: false,
logFile: '/var/log/nginx/axone.access.log',
// For EVM chains, add:
// evmPort: 52545,
// wssPort: 52546,
},
]Run the provided script β it automatically adds access_log to all your nginx chain configs:
bash add-nginx-logs.shCreates per-chain log files at /var/log/nginx/{chain}.access.log.
nano /etc/logrotate.d/nginx-chains/var/log/nginx/axone.access.log
/var/log/nginx/dungeon.access.log
/var/log/nginx/lumen.access.log
/var/log/nginx/regen.access.log
/var/log/nginx/medas.access.log
/var/log/nginx/safrochain.access.log
/var/log/nginx/empeiria.access.log
/var/log/nginx/kiichain.access.log
/var/log/nginx/republic.access.log
/var/log/nginx/pushchain.access.log
{
notifempty
missingok
size 100G
rotate 0
nocreate
}
Also update /etc/logrotate.d/nginx β replace wildcard with explicit files:
# Before:
/var/log/nginx/*.log {
# After:
/var/log/nginx/access.log /var/log/nginx/error.log {cd rpc-stats-api
npm install
cp .env.example .env
nano .env
npm run build
pm2 start dist/index.js --name rpc-stats-api
pm2 save.env options:
PORT=3003
SCRAPE_INTERVAL=5000
ALLOWED_ORIGINS=*
HISTORY_FILE=/var/lib/rpc-stats/history.jsonmkdir -p /var/lib/rpc-statscurl https://stats.rydone.xyz/health
curl https://stats.rydone.xyz/api/stats/axone-1
curl "https://stats.rydone.xyz/api/history/axone-1?range=24h"Edit rpc-gateway/src/data/index.ts β the only file you need to edit to add or configure networks:
const STATS_API = 'https://stats.rydone.xyz'
export const mainnetNetworks: Network[] = [
{
id: 1,
title: 'Axone',
symbol: 'AXONE',
color: '#00d4ff',
chainId: 'axone-1',
statsApi: STATS_API,
logo: '/axone.png',
rpc: 'https://rpc-axone.rydone.xyz',
wss: '#', // '#' = tab disabled
grpc: 'https://grpc-axone.rydone.xyz',
grpcWeb: '#',
rest: 'https://api-axone.rydone.xyz',
evm: '#',
stake: 'https://explorer.rydone.xyz/axone-mainnet/staking/axonevaloper...',
stats: { total: 'β', cached: 'β', avgRps: 'β', curRps: 'β', blockTime: 'β' },
},
]Place logo images in rpc-gateway/public/:
public/
βββ logo.png # site logo
βββ axone.png
βββ dungeon.png
βββ lumen.png
βββ regen.png
βββ medas.png
βββ safrochain.jpg
βββ empeiria.png
βββ kiichain.png
βββ republicai.jpg
βββ pushchain.jpg
cd rpc-gateway
npm install
npm run build
# Output β dist/cd rpc-stats-api
npm run build
pm2 start dist/index.js --name rpc-stats-api
pm2 save
pm2 startup # auto-start on reboot# /etc/nginx/sites-available/rpc-gateway.conf
server {
listen 80;
server_name endpoint.rydone.xyz;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name endpoint.rydone.xyz;
ssl_certificate /etc/letsencrypt/live/rydone.xyz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/rydone.xyz/privkey.pem;
root /var/www/dashboard-endpoint/rpc-gateway/dist;
index index.html;
# SPA routing
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|svg|jpg|ico|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}ln -s /etc/nginx/sites-available/rpc-gateway.conf /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
certbot --nginx -d endpoint.rydone.xyz# /etc/nginx/sites-available/stats.conf
server {
listen 443 ssl http2;
server_name stats.rydone.xyz;
ssl_certificate /etc/letsencrypt/live/rydone.xyz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/rydone.xyz/privkey.pem;
location / {
proxy_pass http://localhost:3003;
proxy_http_version 1.1;
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 https;
}
}ln -s /etc/nginx/sites-available/stats.conf /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginxcd rpc-gateway
npm run build
# nginx serves dist/ automatically β no restart needed| Endpoint | Method | Description |
|---|---|---|
/health |
GET | API health check + all chain status |
/api/stats |
GET | All chains live stats |
/api/stats/:chainId |
GET | Single chain live stats |
/api/history/:chainId?range=24h|7d|30d |
GET | Historical data for chart |
/api/raw/:chainId |
GET | Raw Prometheus metrics (debug) |
{
"chainId": "axone-1",
"name": "Axone",
"testnet": false,
"hasEvm": false,
"hasWss": false,
"latestBlockHeight": 3831560,
"blockTime": 5.66,
"syncing": false,
"totalRequests": 48291,
"cachedPct": 0,
"avgRps": 1,
"curRps": 2,
"numPeers": 9,
"memUsageMB": 376.1,
"goRoutines": 186,
"scrapeOk": true,
"timestamp": 1773777020432
}{
"chainId": "oro_1336-1",
"name": "Kiichain",
"hasEvm": true,
"hasWss": true,
"latestBlockHeight": 29554258,
"evmBlockNumber": 29554257,
"evmChainId": "1336",
"blockTime": 2.78,
"numPeers": 21,
"scrapeOk": true
}1. Add entry to rpc-stats-api/src/chains.ts
2. Create nginx proxy configs for rpc/api/grpc endpoints with access_log /var/log/nginx/{chain}.access.log;
3. Add entry to rpc-gateway/src/data/index.ts
4. Add log file to /etc/logrotate.d/nginx-chains
5. Rebuild and restart:
# Backend
cd rpc-stats-api && npm run build && pm2 restart rpc-stats-api
# Frontend
cd rpc-gateway && npm run buildNo other files need to change.
| Layer | Stack |
|---|---|
| Frontend | React 18, TypeScript, Vite, Tailwind CSS, Recharts, Zustand |
| Backend | Node.js, Express, TypeScript |
| Metrics source | Prometheus (Cosmos SDK built-in telemetry) |
| Traffic tracking | Nginx access logs |
| History storage | JSON file (/var/lib/rpc-stats/history.json) |
| Process manager | PM2 |
| Web server | Nginx |
| SSL | Let's Encrypt / Certbot |
MIT Β© 2026 @RydOne