discover · compare · collections · requirements · contribute · feed · watching · stats · help with your tokens
mrtian2016/routeros-lanpulse · source
Snapshot 0 · 2026-11-04T12:47:28Z · Python · MIT
Content fingerprint
2e30df20b2758f3210ab1856d28edd492411f6a4c1407b8c09ff3b9fa16a3cf0GitHub description at capture
MikroTik RouterOS 的实时流量面板 · A live dashboard for MikroTik RouterOS — flow diagram, event stream, 1-second resolution
README at capture
<div align="center">
# routeros-lanpulse
**A live dashboard for MikroTik RouterOS**
One page that answers: who is using the bandwidth, where traffic enters and leaves,
whether the tunnels are up, and how hot the machines are running.
`RouterOS` · `Prometheus` · `no build step` · `zh / en` · `light / dark`
[中文](README.zh-CN.md) · [**RouterOS setup**](docs/SETUP.md) · [Configuration](docs/CONFIG.md)
### [→ Open the live demo](https://mrtian2016.github.io/routeros-lanpulse/)
The real page, running on a redacted snapshot of a real network. Both themes, both
languages, every panel — nothing to install. Every device name, IP and site name you
see there is a pseudonym produced by the built-in **redaction mode**
(see [Redaction](#redaction)).
</div>
---
## Before you clone: this is a RouterOS dashboard
**A MikroTik router is not one data source among many — it is the foundation.**
Eight of the fifteen panels come from it, including everything that makes the page
worth looking at:
| Needs RouterOS | Optional add-ons |
|---|---|
| WAN throughput + 24 h history | Proxmox VE guests / storage |
| The flow diagram itself | Chassis temperature & fans (IPMI) |
| Per-device LAN traffic *(via `kid-control`)* | NAS capacity & disk health (SNMP) |
| WireGuard peers | Wi-Fi client signal & rates (UniFi) |
| OpenVPN dial-in users | Per-device destinations (NetFlow) |
| Device names *(from DHCP leases)* | Tunnel / ingress accounting (textfile) |
| Half the event stream *(router log)* | |
| Public IP | |
Two things in particular do not port to other platforms: per-device traffic relies on
RouterOS **`kid-control`**, which has no equivalent on OPNsense or OpenWrt, and the
1-second resolution comes from a persistent connection to the RouterOS **binary API**.
If you do not run MikroTik, this project will show you an empty page. That is not a bug —
it is what it is built on.
## Why
Grafana is powerful, but answering "what is my network doing *right now*" means
scanning a dozen panels. lanpulse puts that on one page: a live flow diagram, an
event stream, and a few tables that matter.
- **1-second resolution** — WAN, per-device and tunnel rates are computed by reading
the router's counters directly, so they are not limited by the Prometheus scrape interval.
- **Events, not just graphs** — devices joining and leaving, tunnels dropping, traffic
bursts, disks filling up, fans stopping. Changes are what you actually want to see.
- **Only shows what you have** — no IPMI, no hardware panels; no UniFi, no wireless
section. Turn modules off in the config and they disappear cleanly.
- **No build step** — the frontend is plain ES modules, the backend is Python
standard library only. `docker compose up` and you are done.
## Quick start
**Do [the router-side setup](docs/SETUP.md) first** — a read-only user, the API service and
a `kid-control` profile. It takes five minutes and skipping it is the number one reason the
dashboard comes up empty.
```bash
git clone https://github.com/mrtian2016/routeros-lanpulse.git && cd routeros-lanpulse
cp config.example.toml config.toml # your addresses and names
cp .env.example .env # your passwords
docker compose --profile router up -d
```
> Updating later: `git pull && docker compose pull && docker compose up -d`.
> If you changed the code yourself, add `--build`.
Open `http://<your-host>:9132`.
Profiles select which exporters run — start only what you actually have:
| profile | collects |
|---|---|
| *(none)* | dashboard + Prometheus only |
| `router` | RouterOS (via [mktxp](https://github.com/akpw/mktxp)) |
| `pve` | Proxmox VE |
| `ipmi` | chassis temperatures / fans |
| `snmp` | Synology NAS, switches |
| `netflow` | per-device destination sankey |
| `unifi` | UniFi wireless client signal / rates |
| `all` | everything |
## The demo, and hosting your own
The [live demo](https://mrtian2016.github.io/routeros-lanpulse/) is nothing but `docs/demo/`:
plain HTML built from a **redacted snapshot**, with no backend and no Prometheus behind it.
Drop it on GitHub Pages or any static host, or run it locally.
```bash
python3 -m http.server -d docs/demo 8000
```
It is generated by `scripts/make-demo.py` from a running instance that has redaction
enabled; the generator **refuses to run** against an instance that is not redacted, so
real data never ends up in the demo.
## Settings page
The dashboard itself needs no login on your LAN. **Changing the configuration does.**
Set `ADMIN_PASSWORD` in `.env`, then the ⚙ button opens a settings page where you can edit
`config.toml` directly: the TOML is validated before anything is written, the previous
version is kept as `config.toml.bak`, and changes take effect immediately — only
start-up settings such as the listen port need a container restart.
**Without `ADMIN_PASSWORD` the settings page is closed entirely.** That is deliberate:
the most common way a self-hosted project gets owned is a default password left in place,
so there is no default password to leave.
Sessions are HttpOnly + SameSite=Strict cookies with an 8-hour lifetime; five wrong
passwords from one IP locks it out for five minutes.
## Requirements
**Required**: a MikroTik router running RouterOS, [mktxp](https://github.com/akpw/mktxp)
to scrape it, and Prometheus (included in the compose file). RouterOS 7.x is what this is
developed against; 6.x exposes most of the same metrics but is untested.
**Optional** — turn off what you do not have and the matching panels hide themselves:
Proxmox VE (`prometheus-pve-exporter`), IPMI/BMC (`ipmi-exporter`),
Synology (`snmp-exporter`), UniFi (bundled exporter, API-key based, no local account
needed), NetFlow v9 (bundled collector), and tunnel/ingress accounting via the
textfile scripts in `exporters/textfile/`.
## Configuration
Everything lives in one `config.toml` that holds **identities only — addresses, names,
toggles — never passwords**. Secrets go in `.env`, so you can paste your config into an
issue without redacting it first.
```toml
[router]
host = "192.168.1.1"
wan_interface = "pppoe-out1" # pppoe-outN when dialling, the physical port otherwise
lan_interface = "bridge"
[[hardware]] # one block per machine with a BMC; delete them all if none
title = "Main host"
bmc = "host-a"
instance = "192.168.1.10:9100"
storage = "pve" # pve = storage pools | fs = filesystems | none
[topology.nodes] # the shape of the diagram; delete a node and its links go too
internet = { x = 80, y = 250, w = 110, h = 48, name = "Internet", sub = "Public IPv4" }
ros = { x = 330, y = 250, w = 140, h = 56, name = "RouterOS", core = true }
```
See [`config.example.toml`](config.example.toml) — every option is commented.
## Redaction
For posting screenshots publicly, or letting someone see the dashboard without exposing
your network:
```toml
[redact]
enabled = true
```
Public IPs, private IPs, MAC addresses, domains, device names and site names are replaced
with **deterministic pseudonyms**: the same device always maps to the same fake name, so
the relationships in the diagram stay intact, but the mapping is not reversible.
Public addresses land in `203.0.113.0/24` (RFC 5737 documentation range).
`scripts/leakscan.py` audits the result — it searches the redacted output for real
identifiers and reports anything that slipped through.
## Alerting
Events can be pushed to **Bark** (iOS) and **Telegram**:
```toml
[alerts]
enabled = true
lang = "en" # notification language, independent of the UI language
levels = ["warn", "bad"]
cooldown_sec = 300
startup_quiet_sec = 60
max_per_hour = 20
min_burst_mbps = 200 # separate push threshold for burst events, 0 = off
[alerts.bark]
enabled = true
server = "https://api.day.app"
[alerts.telegram]
enabled = true
api_base = "https://api.telegram.org"
```
Credentials go in `.env`: `BARK_KEY`, `TELEGRAM_TOKEN`, `TELEGRAM_CHAT_ID`.
The settings page has a "send a test notification" button that reports per-channel results.
### Per-event-type switches
Eleven event types each have their own switch. **Types that are off still appear on the
dashboard — they just do not reach your phone:**
```toml
[alerts.kinds]
hw = true # hardware: temperature / fans / disk full / RAID
branch = true # branch tunnels going down and coming back
wan = true # WAN link up/down
vm = true # guests starting and stopping
ovpn = true # OpenVPN dial-in users
wg = false # WireGuard peers (phones roam between networks, this gets chatty)
ts = false # tailnet nodes
lan = false # LAN devices joining / leaving
wifi = false # Wi-Fi join / leave / roam
ingress = false # ingress connection counts
burst = false # traffic bursts
```
Defaults follow one rule: *does this need you to do something?* Actionable types default
to on, informational ones to off. The settings page has the same switches, and writing
from there **preserves your comments** — the standard library has no TOML writer, and
re-serialising the whole file would drop every comment, so the write is line-based.
> Types absent from the config default to **on**. When an upgrade adds a new event type,
> being briefly noisy beats silently swallowing it.
**Dashboard thresholds and push thresholds are different things.** The floors in
`[events]` are set low on purpose — a burst shows up on the panel at 8 Mbps so you can
see trends at a glance. But a normal download should not buzz your phone, so the alert
side has two separate knobs:
- `[alerts] min_burst_mbps` — only bursts above this are pushed (the panel still shows all)
- `[events] burst_level = "info"` — demote bursts so they appear on the panel but never notify
`threshold_level` does the same for temperature and disk events. Events carry their
magnitude in a `v` field, which is what the size filter reads.
Deliberate choices:
- **Startup quiet period** — on boot the router's log buffer gets replayed; without a quiet
window every restart would fire a screenful of notifications.
- **Deduplication and an hourly cap** — a flapping tunnel is the fastest way to make alerts
useless. Better to miss one than to be noisy; noisy alerts are ignored alerts.
- **Sent from a background thread** — pushes go over the internet; a slow or hanging request
must not stall the once-per-second event engine. One channel failing never affects the other.
- **Telegram's API is unreachable from some regions** — point `api_base` at your own reverse
proxy, or set `https_proxy` on the container (urllib honours it by default).
## Architecture
```
browser ──1s──> lanpulse-agent ──┬──> Prometheus ──> exporters
└──> RouterOS API (8728, persistent connection)
```
The agent aggregates one `state.json` from Prometheus, and separately keeps a persistent
RouterOS binary-API connection to read counters every second for the fast lane.
*(Binary API rather than REST: REST writes a login/logout pair to the router log on every
request, and polling once a second overflows the log buffer within minutes.)*
The frontend is plain ES modules with no bundler. Configuration is injected into the page
by the backend, so startup does not wait on any fetch.
## Contributing
Translations are especially welcome — `lanpulse/web/js/i18n.js` is a plain lookup table
that **uses the Chinese source string as the key**, so a missing entry falls back to
readable text instead of a `panel.lan.title` placeholder.
## License
MIT