Skip to content

ryzwan29/dashboard-endpoint

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

17 Commits
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

RydOne Public RPC

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.

License: MIT

Live: endpoint.rydone.xyz Β· Stats API: stats.rydone.xyz


✨ Features

  • 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

πŸ— Supported Networks

Mainnet

Chain Chain ID Type
Axone axone-1 Cosmos
Dungeon dungeon-1 Cosmos
Lumen lumen Cosmos
Regen regen-1 Cosmos
Medas Digital medasdigital-2 Cosmos

Testnet

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

πŸ—‚ Project Structure

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

βš™οΈ Backend Setup (rpc-stats-api)

1. Enable Prometheus on Cosmos nodes

In config/app.toml for each node:

[telemetry]
enabled = true
prometheus-retention-time = 60

In config/config.toml:

[instrumentation]
prometheus = true
prometheus_listen_addr = ":10660"   # unique port per node

Restart node and verify:

curl http://localhost:10660/metrics | grep tendermint_consensus_height

2. Configure chains

Edit 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,
  },
]

3. Set up nginx access logs

Run the provided script β€” it automatically adds access_log to all your nginx chain configs:

bash add-nginx-logs.sh

Creates per-chain log files at /var/log/nginx/{chain}.access.log.

4. Prevent log rotation

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 {

5. Install and run

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.json

6. Create history storage directory

mkdir -p /var/lib/rpc-stats

7. Verify

curl 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"

🌐 Frontend Setup (rpc-gateway)

1. Configure networks

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: 'β€”' },
  },
]

2. Add chain logos

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

3. Build

cd rpc-gateway
npm install
npm run build
# Output β†’ dist/

🚒 Deployment

Backend β€” PM2

cd rpc-stats-api
npm run build
pm2 start dist/index.js --name rpc-stats-api
pm2 save
pm2 startup    # auto-start on reboot

Frontend β€” Nginx static serving

# /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

Stats API β€” Nginx reverse proxy

# /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 nginx

Deploy frontend updates

cd rpc-gateway
npm run build
# nginx serves dist/ automatically β€” no restart needed

πŸ”— API Reference

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)

Example β€” GET /api/stats/axone-1

{
  "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
}

Example β€” GET /api/stats/oro_1336-1 (EVM chain)

{
  "chainId": "oro_1336-1",
  "name": "Kiichain",
  "hasEvm": true,
  "hasWss": true,
  "latestBlockHeight": 29554258,
  "evmBlockNumber": 29554257,
  "evmChainId": "1336",
  "blockTime": 2.78,
  "numPeers": 21,
  "scrapeOk": true
}

βž• Adding a New Chain

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 build

No other files need to change.


πŸ›  Tech Stack

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

πŸ“„ License

MIT Β© 2026 @RydOne

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages