Skip to content

Environment variables

Two programs read environment variables, and they read different ones. The CLI on your machine reads MIKROSCOPE_* variables as flag defaults, plus a handful of credentials that have no flag, plus GRAFANA_URL and GRAFANA_TOKEN. The agent on the router reads unprefixed variables (RATE_HZ, TOKEN …) from its container envlist, which install writes. This page lists both, from cmd/mikroscope/*.go and internal/agent/config.go.

  • A variable sets a flag’s default; the flag on the command line wins.

  • A variable set to the empty string is treated as unset.

  • The CLI never reads a .env file. Export it into the shell first:

    Terminal window
    set -a; . ./.env; set +a
  • Quote a URL that holds & when it lives in a file you source: unquoted, & is a shell operator. .env.example quotes MIKROSCOPE_INFLUX_URL for that reason.

Most deployment flags have no variable. --rate, --buffer, --port, --memory-max, --mem-limit-mb, --capture-mb, --triggers, --floor-hz, --privileged, --ephemeral and --expose are set on the command line or not at all. Commands and flags has every flag.

Variable Flag Read by Default in the code Value in .env.example
MIKROSCOPE_ROUTER --router doctor, install, upgrade, uninstall, status none (required) empty
MIKROSCOPE_SSH_PORT --ssh-port the same ssh config 22
MIKROSCOPE_SSH_KEY --ssh-key the same ssh agent or config empty
MIKROSCOPE_ARCH --arch the deployment verbs arm64 arm64
MIKROSCOPE_AGENT_TAR --agent-tar plan, install, upgrade, image empty (build the agent here) not in the file
MIKROSCOPE_REMOTE_IMAGE --remote-image plan, install, upgrade empty (upload a tar) not in the file
MIKROSCOPE_NAME --name the deployment verbs mikroscope commented out
MIKROSCOPE_VETH --veth the deployment verbs veth-mikroscope veth-mikroscope
MIKROSCOPE_SUBNET --subnet the deployment verbs, record, forward 172.30.10.0/30 172.30.10.0/30
MIKROSCOPE_IFACE_LIST --iface-list the deployment verbs LAN LAN
MIKROSCOPE_ADDR_LIST --addr-list the deployment verbs LANs LANs
MIKROSCOPE_DISK --disk the deployment verbs empty (internal flash) commented out, tmpfs
MIKROSCOPE_LAN_ADDRESS --lan-address the deployment verbs empty commented out
MIKROSCOPE_TOKEN --token the deployment verbs, record, forward empty commented out

MIKROSCOPE_TOKEN is two things at once. For install it is the token written into the agent’s envlist, which the agent then requires. For record and forward it is the token the direct transport sends. The envlist is not a secret store: any RouterOS user with the read policy can list every container’s envlist over the API (verified on RB5009UG+S+, RouterOS 7.24.2, ), which is why the token is the only credential that goes there.

Variable Flag Read by Meaning
MIKROSCOPE_API_ADDR --api record, mark, forward RouterOS binary API host:port; .env.example has 192.168.88.1:8728
MIKROSCOPE_API_USER --api-user record, mark, forward the dedicated API user
MIKROSCOPE_API_PASSWORD none record, mark, forward that user’s password; there is deliberately no flag
MIKROSCOPE_INTERFACES --interfaces forward comma-separated interfaces for monitor-traffic; .env.example has bridge,ether1 commented out

The relay, --log-markers and the API tier fail, or in forward’s case are disabled with a warning, unless --api, --api-user and MIKROSCOPE_API_PASSWORD are all set. The API user has the policy that user needs.

Variable Flag Default in the code Meaning
MIKROSCOPE_INFLUX_URL --influx empty InfluxDB 3 write URL
MIKROSCOPE_LOKI_URL --loki empty Loki push URL
MIKROSCOPE_LOKI_TENANT --loki-tenant empty X-Scope-OrgID
MIKROSCOPE_OTLP_URL --otlp empty OTLP/HTTP metrics endpoint
MIKROSCOPE_GRAPHITE_ADDR --graphite empty carbon plaintext host:port
MIKROSCOPE_ELASTIC_URL --elastic empty Elasticsearch or OpenSearch base URL
MIKROSCOPE_TELEGRAF_URL --telegraf empty Telegraf listener URL (http://, tcp:// or udp://)
MIKROSCOPE_HOST_TAG --host-tag router host tag on every point in every sink; .env.example has rb5009 commented out

Setting a sink’s URL variable is enough to turn that sink on: forward builds every sink whose flag ends up non-empty, from the command line or from the variable. Every one of these names carries the MIKROSCOPE_ prefix: a bare LOKI_URL is read by nothing, and .env.example says so beside MIKROSCOPE_LOKI_URL.

A flag is visible in ps and in a shell history, so every secret the CLI uses is read from the environment only.

Variable Used for
MIKROSCOPE_API_PASSWORD the RouterOS API user
MIKROSCOPE_INFLUX_TOKEN InfluxDB, sent as Authorization: Bearer <token>
MIKROSCOPE_LOKI_TOKEN Loki
MIKROSCOPE_OTLP_TOKEN the OTLP endpoint
MIKROSCOPE_ELASTIC_AUTH Elasticsearch or OpenSearch
MIKROSCOPE_TELEGRAF_TOKEN the Telegraf HTTP listener
GRAFANA_TOKEN dashboards import and dashboards check

dashboards import and dashboards check read GRAFANA_URL (the default of --grafana) and GRAFANA_TOKEN. Neither has the MIKROSCOPE_ prefix. .env.example sets GRAFANA_URL twice, once empty in its LAN-services block and once commented out in the Grafana block, and says the token never goes in the file.

The agent reads these from its container’s environment when it starts. An invalid value makes it print one line starting mikroscope-agent: bad configuration:, which RouterOS puts in its log under the container topic, and exit with status 2.

Variable Agent default Accepted Meaning
RATE_HZ 10 1–100 sampler rate
BUFFER_S 300 10–3600 ring length in seconds
PORT 9123 1–65535 HTTP port
ADDR empty an address bind address. Empty binds :PORT, every address in the container’s network namespace; install always sets it to the agent’s veth address
TOKEN empty when set, every path but /healthz requires Authorization: Bearer <token>
IRQ_TOP_K 8 0–64 interrupt lines kept per sample, busiest first; 0 ships no interrupt lines and no irq_total
MEM_LIMIT_MB 14 8–1024 Go soft memory limit in MiB
FLOOR_HZ 0 0–1000 0 keeps the per-source floors; N puts every level source on N Hz and turns off emit-on-change
SOURCES empty (every source detected) comma-separated names restrict the optional sources to this list; /proc/stat is always read
TRIGGERS softnet-drop,oom,kmsg<=3,reset,irq-err,flash-bad conditions, comma-separated capture trigger conditions
CAPTURE_MB 4 0–256 pinned-bytes budget for captures; 0 turns them off
CAPTURE_PRE_S 5 1–60 seconds kept before the sample a trigger fires on
CAPTURE_POST_S 5 1–60 seconds kept after it
CAPTURE_POLICY first first or last on a full budget: first refuses the new capture, last evicts the oldest
TRIGGER_REFRACTORY_S 10 0–3600 quiet time per condition after it fires
PROC_ROOT /proc a path where /proc is read from; the kernel log is /dev/kmsg only when this is /proc, otherwise dev/kmsg beside the given directory
SYS_ROOT /sys a path where /sys is read from

The names SOURCES accepts are the optional sources /capabilities reports: meminfo, loadavg, softnet, softirqs, interrupts, vmstat, psi, schedstat, self, buddyinfo, yaffs, diskstats, slabinfo, kmsg, thermal, cpufreq, mtd and perf. The trigger conditions and what each compares are on triggered capture.

Before it listens, the agent checks the ring against the container’s own memory.max: RATE_HZ × BUFFER_S × 2 560 B plus CAPTURE_MB must fit, or it refuses to start and names the three variables and --memory-max. If that figure is more than half of MEM_LIMIT_MB, it starts and logs a warning with the limit to raise to. 2 560 B is not itself a measurement: it is the mean line measured on the RB5009 with every source of that date (2 439 B, 4 cores, IRQ_TOP_K 8, RouterOS 7.24.2, 2026-09-12) rounded up. A board with more cores or more interrupt lines writes longer lines, so the check errs open. When the agent cannot read its memory.max, the refusal check does not run.

install and upgrade write the envlist <name>-env with these entries, in this order, and nothing else:

The entries install writes into the agent's envlist
KeyWrittenFromHolds
MIKROSCOPE_TAGalways--namethe ownership marker mikroscope:<name> (managed by mikroscope), written first and removed last; the agent ignores it
RATE_HZalways--rate, default 10, 1–100the sampler rate, in Hz
BUFFER_Salways--buffer, default 300, 10–3600the ring's length, in seconds
PORTalways--port, default 9123, 1–65535the agent's HTTP port
ADDRalways--subnetthe agent's address, the .2 of the /30; the agent binds only there
MEM_LIMIT_MBalways--mem-limit-mb, default 40, 8–1024the agent's Go soft memory limit, in MiB
FLOOR_HZonly when above 0--floor-hz, default 0, 0–1000one cadence for every level source, in Hz
CAPTURE_MBalways--capture-mb, default 4, 0–256the triggered-capture budget, in MiB; 0 turns captures off
TRIGGERSonly when set--triggersthe trigger conditions; unset, the agent uses its default set
TOKENonly when set--tokenthe bearer token the agent requires, from --token or MIKROSCOPE_TOKEN, with or without --expose

.env.example is also the development template for the project’s own devices, so it carries names that no binary reads. Setting them changes nothing:

  • MIKROSCOPE_ROUTEROS, the RouterOS version of the reference device.
  • OPERATOR_HOST_IP, the operator host for push-sink and probe tests.
  • The HEXS_* block (HEXS_ROUTER, HEXS_SSH_PORT, HEXS_SSH_KEY, HEXS_ARCH, HEXS_API_ADDR, HEXS_API_USER, HEXS_API_PASSWORD), kept for a hEX S that has not arrived.