Realtime router & system telemetry API for V6Direct network nodes (AS213413)
A lightweight FastAPI service designed to run on Raspberry Pi PoP routers and similar Linux-based nodes. It exposes system metrics — CPU, memory, disk, and per-interface network counters — over a secured REST API with built-in caching, rate limiting, and a rolling history buffer.
- Full system snapshot — CPU, memory, swap, disks, and all network interfaces in a single request
- Per-resource endpoints — query only the metrics you need
- 30-second in-memory cache — reduces polling overhead; force-invalidate at any time via
POST /stats/refresh - Rolling 60-sample history — lightweight time-series buffer persisted to
history.json - API key authentication — all
/stats/*endpoints requireX-API-Keyheader - Rate limiting — global 60 req/min default; stricter 30 req/min on stats routes via slowapi
- Raspberry Pi temperature support — reads
cpu_thermal/cpu-thermal/coretemp/thermal_zone0viapsutil - Node metadata — exposes hostname, architecture, uptime, ASN, and configurable node role
- Interactive docs — Swagger UI at
/docs, ReDoc at/redoc
- Python 3.10+
- Linux (tested on Raspberry Pi OS / Debian)
Install dependencies:
pip install fastapi uvicorn psutil slowapi pydanticAll configuration is done via environment variables:
| Variable | Default | Description |
|---|---|---|
API_KEY |
changeme |
API key required in X-API-Key header |
NODE_ROLE |
raspi-telemetry |
Node role label (raspi-telemetry or pop-router) |
NODE_ASN |
AS213413 |
ASN reported in node info |
Important: Always set a strong
API_KEYin production. The defaultchangemeis insecure.
API_KEY=your-secret-key NODE_ROLE=pop-router uvicorn code:app --host 0.0.0.0 --port 8000For production, use a systemd service or run behind a reverse proxy (nginx/caddy).
A public demo instance is available and uses the default demo API key:
X-API-Key: changeme
# Health check (no auth)
curl https://raspapi.core01.eu/health
# Full system snapshot
curl -H "X-API-Key: changeme" https://raspapi.core01.eu/stats
# CPU only
curl -H "X-API-Key: changeme" https://raspapi.core01.eu/stats/cpu
# Memory & swap
curl -H "X-API-Key: changeme" https://raspapi.core01.eu/stats/memory
# Network interfaces (all)
curl -H "X-API-Key: changeme" https://raspapi.core01.eu/stats/network
# Filter by interface
curl -H "X-API-Key: changeme" "https://raspapi.core01.eu/stats/network?interface=eth0"
# Last 10 history samples
curl -H "X-API-Key: changeme" "https://raspapi.core01.eu/stats/history?limit=10"
# Force cache refresh
curl -X POST -H "X-API-Key: changeme" -H "Content-Type: application/json" -d '{"reason": "testing", "full": false}' https://raspapi.core01.eu/stats/refreshFor local development, the same default key works unless API_KEY is overridden:
API_KEY=changeme uvicorn code:app --host 127.0.0.1 --port 8000If the public demo exposes Swagger, open
/docs, click Authorize, and enterchangemeas the API key.
All endpoints under /stats/* require an API key passed as a request header:
X-API-Key: your-secret-key
Requests without a valid key return 403 Forbidden.
API root — returns version info and a map of all available endpoints. No auth required.
Lightweight liveness probe. Returns {"status": "ok", "uptime_seconds": N}. No auth required. Suitable for uptime monitors.
Full system snapshot including node info, CPU, memory, disks, and all network interfaces.
Response fields:
node— hostname, platform, architecture, uptime, ASN, node rolecpu— overall %, per-core %, frequency, temperature (if available), load averages (1m/5m/15m)memory— total/available/used MB, percent, swap statsdisks— per-mountpoint: total/used/free GB and percentinterfaces— per-interface: byte/packet counters, error/drop counts, IP addressescache_age_seconds— seconds since last poll
CPU metrics only (usage, per-core breakdown, frequency, temperature, load averages).
RAM and swap usage statistics.
Per-interface traffic counters. Optionally filter by interface name:
GET /stats/network?interface=eth0
GET /stats/network?interface=wg0
Returns 404 if the specified interface is not found.
Static node information: hostname, platform, architecture, Python version, boot time, uptime, ASN.
Rolling history of up to 60 metric samples (CPU %, memory %, swap %). Persisted to history.json across restarts.
GET /stats/history?limit=10
| Query param | Type | Default | Description |
|---|---|---|---|
limit |
int | 60 |
Number of samples to return (1–60) |
Force-invalidates the stats cache and triggers an immediate re-poll. Optionally clears the metric history.
Request body:
{
"reason": "Deploying new config",
"full": false
}| Field | Type | Default | Description |
|---|---|---|---|
reason |
string | null |
Optional reason string included in the response message |
full |
bool | false |
If true, clears the rolling history buffer as well |
| Endpoint group | Limit |
|---|---|
/, /health |
60 req/min |
/stats/* (GET) |
30 req/min |
/stats/refresh (POST) |
10 req/min |
Exceeding limits returns 429 Too Many Requests.
Metric history is saved to history.json in the working directory on every cache update and loaded on startup. The buffer holds a maximum of 60 samples (rolling). Use POST /stats/refresh with "full": true to clear it.
MIT — © V6Direct