Skip to main content

Monitoring & Alerts

Two things worth separating: checking a node right now, and being told when something breaks at 3am. The first is a curl; the second is the monitoring stack.


Health checks

Every role answers the same RPC, whatever its firewall posture. On a node whose RPC is loopback-only, go through the container:

docker exec orbinum-validator curl -s -H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"system_health"}' \
http://localhost:9944

A healthy node returns isSyncing: false and a non-zero peers:

{"jsonrpc":"2.0","result":{"peers":3,"isSyncing":false,"shouldHavePeers":true},"id":1}

Sync progress, when it is still catching up:

docker exec orbinum-validator curl -s -H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"system_syncState"}' \
http://localhost:9944

Compare currentBlock against highestBlock.


Prometheus metrics

Every role exposes metrics on 9615. Where that port listens is the part that differs — see Ports & Endpoints. Keep it on a private interface; the endpoint is unauthenticated, so the firewall is the only thing protecting it.

The metrics worth watching:

MetricWhat it tells you
substrate_block_height{status="best"}Chain is still producing
substrate_block_height{status="finalized"}GRANDPA is still finalizing
substrate_sub_libp2p_peers_countPeering health
substrate_ready_transactions_numberTransaction pool backlog
process_resident_memory_bytesMemory pressure

The alerting stack

node-deploy ships a complete monitoring stack — use it rather than writing rules by hand. testnet/monitoring/ runs Prometheus, Alertmanager (with Telegram delivery) and Grafana in one Compose file, with alert rules already written and tested.

It is generic: you declare which nodes to watch in prometheus/targets/, so the same stack works for one node on your laptop or a fleet on a private VPC.

Everything binds to 127.0.0.1 on the monitoring host. Reach Grafana and Prometheus over an SSH tunnel:

ssh -L 3000:localhost:3000 -L 9090:localhost:9090 user@<monitoring-host>

Each node host also runs the small node-exporter stack from testnet/monitoring/node-exporter/, which reports CPU, memory and disk.

What it already alerts on

The shipped prometheus/rules/ cover the failures that matter:

AlertFires when
FinalityStalledBest and finalized heights diverge
GrandpaRoundStalledNo GRANDPA round progress for 5m
ChainHaltedNo new blocks for 3m
ChainForkDetectedMore than one leaf for 10m
ValidatorHeightDivergenceOne validator falls behind the others
BlockTimeDegradedBlocks arriving slower than target
TransactionPoolBacklogReady transactions above threshold
FinalityStalled is the one to act on first

GRANDPA needs more than two thirds of the set voting. With a small validator set, a couple of nodes offline stops finality for everyone while block production continues — so the chain looks alive from the outside. A growing gap between best and finalized is the signal, and it is the kind of failure that otherwise goes unnoticed for hours.

The monitoring stack deliberately runs no Watchtower: the thing that tells you the chain is broken must not restart itself mid-incident.