Skip to content

Quick install

mikroscope runs an agent in a RouterOS container that samples the router’s kernel at 10 Hz and answers over HTTP on the router’s side of a /30. The CLI on your computer installs it, and install writes these objects, which uninstall removes:

What install writes to your router

  • the install manifest, a file mikroscope/<name>.manifest.txt on the install's disk that lists the options and every object below
  • a veth
  • one address
  • one interface-list membership, unless --iface-list none
  • one address-list entry, unless --addr-list none
  • an envlist
  • the image tar, deleted once the container is extracted, unless --remote-image has the router pull the image
  • the container, and its root mikroscope/<name> on the same disk

Every object carries the comment mikroscope:<name> (managed by mikroscope)

mikroscope plan prints every command before anything is written.

uninstall removes by exact tag plus identity, never by pattern, and fails naming the step if anything remains.

install writes nothing outside the router: the collector and the Grafana dashboards are a separate, optional step (See it in Grafana).

Need Value
RouterOS 7.24 or later
Architecture arm64, arm or x86_64; not MIPS, TILE or PPC
container package installed and enabled
Device mode container=yes, confirmed with a button press or a power cycle

You also need a computer with ssh access to the router as an admin user, with a key or an ssh agent: the CLI runs ssh in batch mode and cannot answer a password prompt. Requirements has the details and what doctor checks.

Terminal window
curl -fsSL https://raw.githubusercontent.com/jmrplens/mikroscope/main/install.sh | bash

In PowerShell on Windows:

Terminal window
irm https://raw.githubusercontent.com/jmrplens/mikroscope/main/install.ps1 | iex

The script installs the newest release and refuses an archive whose SHA-256 is not the one the release published. Install the CLI has the same steps by hand.

Terminal window
mikroscope doctor --router admin@192.168.88.1 --remote-image jmrplens/mikroscope-agent:1.6.1

doctor reads the router and writes nothing. It prints one line per check, marked ok, MISSING or WARN, and ends with doctor: every prerequisite is met. A MISSING line is followed by its fix:

MISSING interface list LAN exists (found=0)
fix: --iface-list none: no firewall rule here needs the veth in an interface list. Or create it: `/interface/list/add name=LAN`

Apply the fix, or add the flag it names to this command and to install below, and run doctor again until nothing is MISSING. A WARN line does not stop the install.

Terminal window
mikroscope install --router admin@192.168.88.1 --remote-image jmrplens/mikroscope-agent:1.6.1

install runs the same checks, reads the router’s architecture, and prints every RouterOS command it will run, ending with nothing above has been written yet. It then asks write the objects above to the router? [y/N]. After the writes it probes the agent from your computer:

install done: 6 step(s) created
probing http://172.30.10.2:9123/healthz from this host …
direct transport ok: agent 1.6.1 (<commit>) built <time>, 10 Hz, seq 7, 0 slipped, 2ms round trip

The router pulls the image from Docker Hub itself: nothing is uploaded, and nothing is set in /container/config. If the probe cannot reach the agent, it says whether the container runs; Network access has the three ways to reach it.

Terminal window
mikroscope status --router admin@192.168.88.1

status reads the install manifest on the router, prints how many objects each step holds, and probes the agent:

agent: 1.6.1 (<commit>) built <time>, 10 Hz, seq 14 (oldest 1), up 1s, 0 slipped, 1ms round trip

From a host on the router’s LAN, curl http://172.30.10.2:9123/healthz answers {"ok":true,…}.

Optional, and nothing here writes to the router. The dashboards read a store, and the collector, mikroscope forward, is what fills it: it pulls the samples from the agent and writes them to the sinks you name. With an InfluxDB 3 and a Grafana already running, start it and leave it running:

Terminal window
export MIKROSCOPE_INFLUX_TOKEN=… # the store's token; leave it out for a store without auth
mikroscope forward --influx http://localhost:8181 --influx-db mikroscope

Once samples have arrived, run dashboards publish from another shell with the same MIKROSCOPE_INFLUX_TOKEN, the collector’s sink flags and your Grafana. It creates the store’s datasource, publishes its dashboard and exits:

Terminal window
export GRAFANA_TOKEN=… # a Grafana service-account token with the Admin role
mikroscope dashboards publish --influx http://localhost:8181 --influx-db mikroscope --grafana http://localhost:3000
folder "mikroscope" (<uid>) created
influxdb: datasource mikroscope-influxdb (influxdb) created
influxdb: dashboard http://localhost:3000/d/mikroscope-influxdb/…
  • Too early. Run before the store holds a sample, it publishes the compiled defaults and prints could not ask the datasource which measurements it holds. Run it again once data has arrived and it replaces the dashboard.
  • From the collector. Add --grafana http://localhost:3000 to forward, with GRAFANA_TOKEN in its environment, and it publishes the same way at every start, before collecting.
  • Another address. When Grafana reaches InfluxDB by another address than the collector does, pass that address in --grafana-datasource-url. With Grafana in a container, localhost is the container itself: use InfluxDB’s name on the Docker network, such as http://influxdb:8181, or the host’s LAN address.
  • The interface panels also need the RouterOS API tier.

Set up in Grafana covers Prometheus and the other stores, importing by hand, and checking every panel.

Install methods compares them.

  • First recording: record a window, mark it and plot it.
  • Run the collector: send the samples to Prometheus, InfluxDB 3 or nine other sinks.
  • Set up in Grafana: the dashboards for Prometheus and the other stores, from the collector, the CLI or by hand.
  • Dashboards: what every section and panel shows.
  • It merges with the RouterOS API and does not replace it: per-interface traffic comes from the API, because the container sees only its own network.
  • The kernel counts CPU time in ticks of 10 ms, so one 100 ms sample resolves one core in steps of 10 %.
  • A source a board does not have is absent from the output, never zero.

How it works has the full list.