Self-hosted web application for managing MikroTik device fleets. Monitor, configure, upgrade, and backup your devices from a single dashboard with real-time WebSocket updates.
- Real-time dashboard — device status cards with WebSocket live updates (60s polling, configurable per device)
- Metric & SFP optical graphs (v1.42.0+, CPU/memory v1.53.1+) — per-device history charts for CPU load, memory usage, voltage, temperature, fan speed and any other
/system/healthsensor a model exposes (standalone card, auto-scaled axis, 1h/6h/24h/7d/30d). CPU and memory ride along on the regular poll, so they cost no extra device I/O and are graphed on every transport, SNMP-polled devices included. Fibre ports also get SFP optical graphs — Rx/Tx power (dBm), module temperature and supply voltage — via a Traffic/Optical switch on the traffic card. Sampled every 5 minutes, kept 90 days by default (METRICS_RETENTION_DAYS, adjustable in Settings); useful even without an SNMP monitoring system. Works for offline devices, and on models with no sensors at all - Metric threshold alerts (v1.58.0+) — fire a webhook when a device's CPU load, memory usage or temperature crosses a threshold, and an optional recovery webhook when it drops back below. Thresholds set globally in Settings → Metric alerts (CPU/memory default 90%, temperature off by default) or overridden per device (
0disables a metric for that device). An alert only fires after the value stays over the limit for a few consecutive samples (default 3), so brief spikes stay quiet - SNMP monitoring — lightweight SNMPv2c polling (CPU, memory, uptime, temperature, voltage). Sensors are read from the named health table as well as the scalar OIDs (v1.67.1+), so boards that publish only the former — most of the ax generation — report the same temperature over SNMP as over SSH
- Three connection methods — SSH, REST API, or SNMP-only per device
- SNMP as supplementary — SSH/REST devices can also use SNMP for faster status checks
- SNMP-first monitoring (v1.46.0+) — optionally poll routine status and traffic over SNMP (IF-MIB 64-bit counters), opening SSH/REST only on demand for actions and detail tabs — keeps long-lived SSH sessions off routers that don't like them. Global toggle or per-device (Default / SNMP / SSH); off by default, never forced
- Site grouping — organize devices by physical location; search sites by name, location or description (v1.63.0+)
- Duplicate a device (v1.63.0+) — clone an existing device from its page: give the copy a name and a host, everything else is inherited (credentials, site, tags, connection method, ports, poll interval). The copy is made server-side, so the stored credentials come with it
- Read-only RouterOS account warning (v1.64.0+) — your role here and the rights of the RouterOS user stored for a device are independent. A device whose RouterOS account has no
writepolicy carries aread-onlybadge on its card and a note on its page naming the account, so you learn about it when adding the device rather than when an upgrade or a backup is rejected. Test Connection reports it too - Device tags — assign tags with autocomplete, filter by multiple tags (Shift+click)
- Bulk editing — select multiple devices, change connection parameters in one action
- Enable/disable — disabled devices skip monitoring, dimmed in UI
- Import from scan — discover and add devices from network scan results
- Export / import between instances (v1.45.0+) — export selected devices (by site or individually) to a passphrase-encrypted
.mikrbundleand import them into another mikr instance, credentials included; ideal for seeding demo/staging from production
- Bulk CLI commands — execute on multiple devices with live WebSocket output
- Run-as credential override — optionally run a bulk command under your own RouterOS login for that one execution; credentials are never stored or logged
- Tag-based target selection — toggle all devices carrying a tag on/off with one click, alongside Select All/Online and manual picking
- RouterOS upgrades — check for updates + upgrade with real-time progress
- Active Tasks tray — running upgrades stay visible from any page and survive a reload; each task keeps its own log (v1.54.0+)
- Firmware upgrades — write firmware + automatic reboot
- Config backup & export — save device configurations to database. (v1.55.0+) Every export is verified complete before it is stored, and backups taken earlier are checked on upgrade — any that do not hold a whole config are marked incomplete so they are never mistaken for a usable restore point
- Side-by-side diff — compare any two backups visually
- Fleet backup health (v1.69.0+) — the Backups page opens with how many devices are covered and what is wrong with the rest, split into no backup, incomplete latest export, overdue schedule (two consecutive missed runs, so a single offline run raises nothing) and no schedule at all. Click a count for the devices behind it and back one up or give it a schedule from there. Disabled and SNMP-only devices are left out, and nothing is asked of a device to produce it
- Backup scheduling — automated exports with time-of-day selection and flexible intervals (2h to 7d)
- Site-wide backup schedules (v1.41.0+) — set one schedule per site; every device in the site inherits it and devices added later are included automatically. Per-device overrides are kept; opt a new device out from the Add Device form
- Global default backup policy (v1.63.0+) — Settings → Default backup policy sets a fallback for sites that have no schedule of their own, so a newly created site is covered without opening the Backups page. A site schedule overrides it, and a per-device schedule set by hand overrides both. Off by default
- Built-in syslog receiver (UDP + TCP) — the Manager ships both UDP and TCP listeners on port
5514that ingest MikroTik syslog messages, persist them to SQLite, and stream live to the UI over WebSocket. TCP is useful when UDP is blocked by firewalls or when you want guaranteed delivery — RouterOS 7.x supportsRemote Log Protocol: TCPnatively. - Native RouterOS format — topics and messages appear exactly as in
/log print(works out of the box withremote-log-format=default; also accepts<PRI>-prefixed andbsd-syslog=yesRFC3164 forms) - Unified Logs page — all devices in one stream with colored severity stripe, filters (device, severity, topic, text search), time range selector (
All time/Last 1h/6h/24h/7d), Load older pagination, pause and auto-scroll - Per-device Logs tab — focused view on the device detail page for troubleshooting a specific router
- Multi-IP device correlation — logs are matched to the right device by any interface IP (collected each monitor poll), so the syslog source IP doesn't need to equal the management IP and
src-address=pinning is optional - Per-device retention override — raise the row cap on chatty core/border routers, lower it on quiet APs, so a log-storm on one device can't evict logs from the rest of the fleet
- Setup Guide modal — one click generates a copy-paste MikroTik CLI snippet and an optional Command Template to apply the config to every device at once
- On-device syslog + RouterOS
dstnat(if running mikr inside a MikroTik Container App) — see the full install guide at mikr.app/install.html#container - Webhooks — fire an HTTP notification on device online/offline/not-accessible/rebooted, upgrades, backups, new RouterOS releases, CVE and vendor-patch alerts, LTE data thresholds, and metric thresholds (CPU/memory/temperature). Ready-made JSON, ntfy and Discord formats, optional HMAC-SHA256 signing, and per-event custom message templates
- Webhooks to any REST API (v1.52.0+) — the Custom format adds your own headers, body template and HTTP method (POST/GET/PUT), so a webhook can drive an SMS gateway, ticketing system or anything else with a REST endpoint. Write the body your target expects (e.g.
{"to":["+48123456789"],"text":"{{summary}}"}); placeholders work in the URL too, for APIs that take query parameters. Substituted values are escaped for yourContent-Type, so quotes in device names or error text can't malform the request. Header values are encrypted at rest like device passwords and are never returned to the browser - Prometheus / Grafana export (v1.59.0+) — an opt-in
/metricsendpoint in Prometheus text-exposition format for scraping fleet metrics into a time-series database for long-term graphing. Exposes device up/down, CPU, memory, uptime, temperature, voltage, power, and per-interface receive/transmit rates (mikr_interface_rx_bits_per_second/_tx_bits_per_second) — labelled by device, host, site and interface. Enable and set an optional scrape token under Settings → Prometheus export (orMETRICS_ENABLED/METRICS_TOKEN). Reads from the manager's own database, so a scrape adds no load on your routers. InfluxDB users can pull it in via a Telegrafprometheusinput — see the Prometheus & Grafana section of the install guide; a starter Grafana dashboard is at grafana-dashboard.json - Zabbix template (v1.61.3+, per-sensor discovery v1.61.5+) — zabbix-template.yaml monitors the manager over its REST API and, through it, every device it polls — no SNMP or SSH access to the routers is needed, and no Prometheus or Grafana either. Devices are discovered automatically from the API, so each one arrives with its own items (online, CPU, memory, temperature, voltage, RouterOS version, firmware, last poll) and triggers (offline, thresholds, RouterOS update available, firmware behind, stale data). Fleet-level items cover service health, database size, CVE severities, patch gaps, licence headroom, syslog throughput, blocked attackers and failed tasks. Needs one viewer API key from Settings → API keys
- IP range scanning — CIDR, dash ranges, single IP (probes SSH + HTTPS + HTTP)
- Neighbor discovery — MNDP / LLDP / CDP with clickable links to managed devices
- MAC→IPv4 cross-reference — resolves link-local IPv6 neighbors to real addresses
- Full interface discovery — all types: ethernet, SFP, bridge, VLAN, bonding, wireless, WireGuard, EoIP, GRE, PPPoE
- Grouped interface view — Ethernet/Physical, CAPsMAN/WiFi, Bridge/VLAN/Bond, Tunnels/VPN, categorized with chips
- Physical port map (redesigned v1.48.0+, glyphs v1.62.0+, VLANs v1.65.0+) — a compact faceplate: each port is a slot with a link-speed LED bar, an activity light, a live-traffic sparkline and small marks inside the cage for delivered PoE (⚡) and a discovered neighbour (→). Copper and SFP ports are drawn as separate blocks (fibre ports as distinct SFP cages); wide 24/48-port switches scale the whole two-row faceplate to fit the width (no scroll), and full per-port detail — wattage, optical readings, the neighbour's identity — is a hover away on the desktop and a tap away on a phone, where ports are labelled by number so the whole switch fits the screen. Each port also shows its VLAN role — access or trunk, with the tagged VLANs and the native VLAN — read from whichever place the model keeps it (bridge VLAN table or switch chip) and presented identically for both. A VLAN picker above the faceplate highlights every port carrying the chosen VLAN, filled where it leaves untagged and outlined where it leaves tagged. On models where enabling bridge VLAN filtering costs the hardware offload, the map says so
- VLAN editing (v1.67.0+) — an Edit mode switch on the Interfaces card, for administrators and operators only and off on every page open, opens a VLAN editor: add the VLANs you need, then give each port a role — Access in one VLAN or Trunk carrying several, tagged. The panel works out how the hardware wants to be configured: on models that keep their hardware offload with a filtering bridge it writes the bridge VLAN table, and on models that would lose it (QCA switch chips) it configures the switch chip instead, so the traffic stays offloaded — without asking which kind of device you have. A switch with no bridge configured yet is a normal starting point: saving creates the bridge, moves the ports into it, writes the VLAN table and enables filtering last, the one order that does not interrupt traffic partway through. Tick management on a VLAN and the device gets its own interface in it, on the bridge. The interface the panel reaches the device through is identified from the device's own IP configuration — including when the address sits on a VLAN interface riding a physical port — and kept out of the change; where that path runs through the bridge itself, the editor refuses to delete that VLAN, to take the bridge out of it, or to leave it reaching no port. Review changes shows the exact RouterOS commands before anything is written, a configuration backup is taken first and a failed backup cancels the change, and the device is given a rollback that fires in three minutes unless the change is confirmed — closing the browser does not stop it. VLAN names are stored on the device as the VLAN row's comment. Ports nobody has configured are left exactly as they are. On a device with several bridges (v1.68.0+) you choose which one you are editing, every port shows the bridge it belongs to and the VLANs it carries — including ports that are in no bridge themselves but feed one through a VLAN interface — and the panel reports which bridge holds the hardware offload where the device says so. A port belonging to another bridge cannot be given a role here, and a bridge whose ports are VLAN interfaces (one bridge per VLAN, the pre-
vlan-filteringway) is shown read-only: the configuration is displayed in full, but mikr does not write that scheme - PoE indicators — lightning bolt icon with power, voltage, current in tooltip
- PoE budget (v1.71.0+) — on switches with PoE-out, on desktop and phone, a card showing watts delivered against the watts the model can deliver, and how many ports are actually feeding something. The ceiling comes from a per-model table (RouterOS reports consumption but never a budget): a fixed figure for switches with an internal PSU, the fitted-PSU count for a CRS320, and current limit x measured supply voltage for switches you power yourself. CRS328-24P also shows its three per-group ceilings. Models outside the table show the draw without a bar, and any device can have its budget set by hand for a non-standard supply
- DHCP leases — view all leases with IP, MAC, hostname, status badges, and expiry time
- Wireless clients — connected clients with signal strength, TX/RX rates, uptime, and IP from DHCP
- Wi-Fi password change — set new WPA2/WPA3 passphrases from the Wi-Fi tab for modern RouterOS 7 Wi-Fi (
/interface wifi, incl. CAPsMAN); profile-aware, write-only (current password never shown), admin-only, audited (v1.49.1+) - Auto-refresh — DHCP and wireless tables update every 30s while visible, disconnected clients disappear automatically
- IPsec tunnels — configured peers with established/not established state, traffic counters, uptime; grouped as an expandable Peer → Policies tree with per-peer established/total policy counts (v1.43.0+)
- WireGuard peers — endpoint, last handshake (color-coded by recency), TX/RX counters; Add client wizard (v1.50.0+) picks the next free tunnel IP (v4 + v6), generates the keypair, writes the peer and returns a QR + downloadable
.conf— private key shown once, never stored (admin only) - LTE monitoring — per-modem signal (RSRP/RSRQ/SINR/RSSI with bars), operator, band/cell info, session uptime, optional cell-tower location (CellMapper / OpenCelliD), and modem firmware upgrade
- LTE SMS inbox (v1.44.0+) — read SMS received by an LTE modem (time, sender, text) under the device LTE tab, with a sender/text filter and unread tracking; messages are stored in mikr so the history survives the modem auto-erasing its own inbox
- LTE data-usage counter (v1.47.0+) — set a monthly data limit (GB) per LTE device and mikr accumulates the LTE transfer for the calendar month, showing a used/limit bar on the LTE tab and firing a webhook at a warning % (default 80%) and at 100% — once each per cycle. Counts LTE interfaces only; the figure is an estimate accumulated from polling (not the carrier balance). Optional per-device Owner phone is carried in the alert payload for SMS bridging via webhooks
- BGP / OSPF status (v1.38.0+) — a Routing tab on devices running BGP or OSPF: live BGP sessions with remote AS, state, uptime and received prefix count, plus OSPF neighbors with state, adjacency time and area. Surfaces details RouterOS doesn't expose over SNMP (per-peer prefix counts, OSPF neighbors); auto-refreshes, shown only where the protocol is active
- BGP history graphs (v1.39.0+) — each BGP peer keeps a 5-minute history of its received prefix count and session up/down state, charted under the BGP table (auto-scaled Y axis, downtime strip, 6h/24h/7d/30d ranges). Click any BGP row to chart that peer
- IP services — see all MikroTik services (SSH, API, WWW, Winbox, FTP) as colored pills, toggle enable/disable with safety checks
- Route counting — per-protocol breakdown (static, connected, BGP, OSPF, RIP, etc.)
- Network topology map — interactive per-site map built from MNDP/LLDP neighbour discovery: managed devices as draggable cards (status, model, CPU/RAM, IP), physical links styled by speed / bond / wireless, and unknown neighbours as dashed nodes. More reliable link discovery, an empty-state that explains why no links were found, and IPs shown on unmanaged nodes — resolved from LLDP or, when discovery advertises none, from the ARP tables of your managed devices (ARP fallback v1.60.0+)
- Phone layout (v1.61.0+) — a one-column layout built for incident response from a phone, replacing the responsive pass from v1.36.0: bottom tab bar (Devices / Upgrades / Logs / More) instead of the slide-in drawer, device cards with threshold-coloured CPU / memory / temperature bars grouped by site, pull-to-refresh, role-gated swipe-to-reboot, a device page whose tabs are generated from what the device actually reports (with swipe between them) and the same port faceplate the desktop draws, a bottom action bar with a consequence-stating confirm sheet, and a streaming Command output screen shared with the desktop. Landscape is supported; an expired session is re-authenticated over the screen you were on; the live-connection state and the time the readings froze are always visible. (v1.70.0+) The device page also carries the metric history the desktop shows — CPU, memory, temperature and every health sensor the board reports, over 1h to 30d, with the tiles doubling as the picker: tap CPU, RAM or Temperature to chart it. Desktop layout unchanged; Topology stays desktop-only
- Installable on a phone (v1.61.0+) — Add to Home Screen gives mikr its own icon and a full-screen window. Served over HTTPS it also caches the interface itself, so launching it while the manager is unreachable shows the real UI with a clear error rather than a browser page; nothing from the API is ever cached, so every reading on screen is live. Over plain HTTP the icon and full-screen window still work — browsers only allow the offline cache on a secure origin
- HTTPS / TLS — optional HTTPS server on port 3443; auto-generated self-signed cert or bring your own; HTTP and HTTPS run in parallel; WebSocket (WSS) works automatically over HTTPS
- Role-based access — superadmin / admin / operator / viewer
- Per-site access control (v1.33.0+) — scope any non-superadmin user to specific sites; the role decides what they can do, the assigned sites decide where. Scoped users only see and act on their sites everywhere (dashboard, devices, logs, backups, live status, bulk commands/upgrades), enforced server-side. Superadmin manages users and grants site access; unrestricted users keep full-fleet access. (v1.40.0+) Access can be assigned both ways — per user, or per site straight from the Add/Edit Site form (tick which scoped users get the site, instead of editing each user)
- JWT authentication — access token (15min) + refresh token (7d)
- RouterOS CVE alerting — each device's RouterOS version is matched daily against the public NVD vulnerability feed. Dedicated Security page with severity/site filters, a per-device Security Advisories card, a
N CVEbadge on device cards, and a High/Critical dashboard banner. Each entry shows the CVSS score/vector, summary, advisory link, and the version that fixes it. Scoped to RouterOS 7; optionalcve-alertwebhook. Informational only — never blocks upgrades or commands - Vendor patch-gap detection (v1.51.0+) — a second, independent security signal that catches what CVE databases structurally cannot. mikr reads MikroTik's own release changelogs for the branches you actually run and flags any device below a release that fixed something security-related, using MikroTik's
!)marker plus any named CVE id. Kept deliberately separate from the CVE feed, because the two make different claims: a CVE says "this device is vulnerable" (NVD supplies an affected range), a patch gap says only "a security release exists on your branch and you're below it" — a changelog names the fix version, never the affected range, so mikr never infers one from the other and never guesses across branches. Security lines are snapshotted on first sight and re-checked daily: when the vendor edits or removes one after publication, mikr keeps the original text and shows the edit. Security → Vendor patches tab, device-page card,security-patch-availablewebhook - Auto-block / Simple IDS — detects repeated failed logins from the syslog stream, aggregates them per source IP across the whole fleet, and past a threshold (default 5 / 10 min) blocks the IP by maintaining a
mikr-blocklistfirewall address-list with a native 72h timeout. Per-device opt-in; Audit mode (list candidates, block by hand) or Auto-block (block at threshold); whitelist (manual CIDRs + auto private-range + hard-whitelisted server IP). Address-list only — you add one drop rule that references the list; mikr never touches your firewall chains. Candidates / Blocked / Whitelist tabs on the Security page - GeoIP rule generator — pick countries and generate an idempotent RouterOS firewall script sourced from ipdeny.com: Blocklist (drop the selected countries; inbound/outbound,
raworfilter) or Allowlist (keep only the selected countries, drop the rest — auto-adds an established/private/always-allow safety block so it can't lock you out); IPv4/IPv6, optional weekly auto-refresh; saved as a Script command template and installed via the existing Deploy flow - Two-factor authentication (TOTP) — opt-in per user, RFC 6238 compatible with Google Authenticator / Authy / 1Password / Microsoft Authenticator; AES-256-GCM-encrypted secrets; 8 single-use backup codes; admin reset for lost devices
- Passkey / WebAuthn / FIDO2 sign-in — additive second factor alongside TOTP: Touch ID, Face ID, Windows Hello, Apple/Google passkey, YubiKey. Multiple named passkeys per account with last-used info, admin reset, counter-regression check against cloned authenticators. Requires HTTPS on a real domain (WebAuthn spec forbids IP RP IDs) — LAN-IP installs see an explicit "Unavailable" notice rather than silent failure
- Encrypted passwords — AES-256-GCM for stored device credentials
- Dark / Light theme — toggle in sidebar, persisted in localStorage
- Settings UI for runtime knobs (v1.30.0+) — admin Settings → System configuration: 47 knobs across 16 groups (CVE feed enable/key/interval, activity-log retention, monitor poll cadence and concurrency, traffic and syslog retention, metric alert thresholds, LTE data usage, auto-block / IDS, Prometheus export, the default backup policy, backup and upgrade scheduler intervals, JWT access/refresh expiry, WebAuthn RP ID / name / origins, log level, default SSH / REST API port for new devices). Edit live in the browser, no
docker-composeedit or container restart, secrets encrypted at rest with AES-256-GCM. Sticky left subnav, one card per group, "from env" badge on any field locked by an environment variable. - Environment variables always win — anything you set in
.env/ docker-compose stays the source of truth and renders as read-only in the UI with a "from env" badge. GitOps-friendly: existing compose-first deployments don't change behaviour after the upgrade. Bootstrap values (PORT,HOST,JWT_SECRET,ENCRYPTION_KEY,TLS_*,SYSLOG_PORT) stay env-only by design — they're either consumed before settings are loaded, or moving them would invalidate every stored secret on change. - Optional
.rscmirror to/data/exports(v1.30.0+, closes #28) — toggle in Settings → External export. After each successful backup, also writes the RouterOS script export to/data/exports/<site>/<device>.rsc— one file per device, overwritten on each new backup. Mount/data/exportson a separate host volume for disaster recovery, point a git checkout at it for a free change-history (commit after each write), or rclone it to a NAS / cloud for 3-2-1 backups. Mikr never deletes from this volume; cleanup is yours (git rm / shell).
Full install guide, including how to deploy on a MikroTik Container App and configure the RouterOS
dstnatrule for UDP 5514 (syslog): see mikr.app/install.html.
# Pull image
docker pull ghcr.io/hreskiv/mikr:latest
# Create project directory
mkdir -p /opt/mikr/data && cd /opt/mikr
# Create docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
mikr:
image: ghcr.io/hreskiv/mikr:latest
container_name: mikr-manager
restart: unless-stopped
ports:
- "3000:3000"
- "3443:3443" # HTTPS (optional, requires TLS_ENABLED=true)
- "5514:5514/udp" # Syslog UDP (optional — omit if not using the Logs page)
- "5514:5514/tcp" # Syslog TCP (optional — useful when UDP is blocked)
volumes:
- ./data:/app/data
environment:
- PORT=3000
- HOST=0.0.0.0
- STORAGE_ADAPTER=sqlite
# JWT_SECRET and ENCRYPTION_KEY are auto-generated on first start and saved
# to ./data/.secrets.json (mode 0600). Back up the data/ directory!
# Override here if you want to set your own:
# - JWT_SECRET=$(openssl rand -hex 48)
# - ENCRYPTION_KEY=$(openssl rand -hex 32)
EOF
# Start
docker compose up -d
# Create default admin user (first run only)
docker exec mikr-manager node scripts/seed.jsOpen http://<host>:3000, login: admin / admin
Production: Change the default password immediately. Create a dedicated MikroTik user group with only the required policies instead of using
adminwith full access:/user/group/add name=manager-group policy=ssh,reboot,read,write,sensitive,rest-api,policy,!local,!telnet,!ftp,!test,!winbox,!password,!web,!sniff,api,!romon /user/add name=mikr group=manager-group password=YOUR_PASSWORDThis limits the blast radius if the manager is compromised.
docker pull ghcr.io/hreskiv/mikr:latest
mkdir -p /opt/mikr/data
docker run -d \
--name mikr-manager \
--restart unless-stopped \
-p 3000:3000 \
-p 5514:5514/udp \
-p 5514:5514/tcp \
-v /opt/mikr/data:/app/data \
-e PORT=3000 \
-e HOST=0.0.0.0 \
-e STORAGE_ADAPTER=sqlite \
ghcr.io/hreskiv/mikr:latest
# JWT_SECRET and ENCRYPTION_KEY are auto-generated and persisted to
# /opt/mikr/data/.secrets.json on first start. To use your own values,
# pass: -e JWT_SECRET=$(openssl rand -hex 48) -e ENCRYPTION_KEY=$(openssl rand -hex 32)
docker exec mikr-manager node scripts/seed.jsAll variables below are optional with sensible defaults. From v1.30.0, most of them are also editable from Admin → Settings → System configuration without a compose edit or restart — when set as an env var here, they take precedence over the UI value and show as locked with a "from env" badge. Bootstrap values (marked bootstrap below) stay env-only.
| Variable | Required | Default | Description |
|---|---|---|---|
JWT_SECRET |
No | auto-generated | Auto-generated on first start, persisted to data/.secrets.json. Override by setting env. Generate your own: openssl rand -hex 48 |
ENCRYPTION_KEY |
No | auto-generated | 64 hex chars (32 bytes). Same auto-gen + persist as JWT_SECRET. Generate your own: openssl rand -hex 32 |
PORT |
No | 3000 |
Server port |
HOST |
No | 0.0.0.0 |
Bind address |
STORAGE_ADAPTER |
No | sqlite |
Storage backend |
LOG_LEVEL |
No | info |
Log level |
MONITOR_INTERVAL_MS |
No | 60000 |
Device polling interval (ms) |
MONITOR_CONCURRENCY |
No | 10 |
Parallel device checks |
TLS_ENABLED |
No | false |
Enable HTTPS server |
HTTPS_PORT |
No | 3443 |
HTTPS server port |
TLS_CERT_PATH |
No | auto-generated | Path to custom TLS certificate (PEM) |
TLS_KEY_PATH |
No | auto-generated | Path to custom TLS private key (PEM) |
SYSLOG_ENABLED |
No | true |
Enable the built-in UDP syslog receiver |
SYSLOG_PORT |
No | 5514 |
UDP port for the syslog listener |
SYSLOG_TCP_ENABLED |
No | true |
Enable the built-in TCP syslog receiver (parallel to UDP) |
SYSLOG_TCP_PORT |
No | 5514 |
TCP port for the syslog listener (defaults to SYSLOG_PORT) |
SYSLOG_RETENTION_DAYS |
No | 7 |
Drop log rows older than this many days |
SYSLOG_MAX_ROWS_PER_DEVICE |
No | 10000 |
Global per-device row cap (overridable per device in the UI) |
CVE_ENABLED |
No | true |
Enable RouterOS CVE alerting (daily NVD feed match) |
NVD_API_KEY |
No | (none) | Optional NVD API key — raises the fetch rate limit (not required) |
CVE_CHECK_INTERVAL_MS |
No | 86400000 |
How often to refresh the NVD feed (default 24h) |
IDS_ENABLED |
No | false |
Enable Auto-block / Simple IDS (block source IPs of repeated failed logins; per-device opt-in, tune the rest in Settings) |
EXPORT_RSC_ENABLED |
No | false |
Mirror the latest .rsc export to /data/exports/<site>/<device>.rsc after each backup (v1.30.0+). Mount /data/exports to a host volume for DR / git / rclone. |
BACKUP_DEFAULTS_ENABLED |
No | false |
Global default backup policy for sites with no schedule of their own (v1.63.0+). Interval, start time and retention are BACKUP_DEFAULTS_INTERVAL_MS / _START_TIME / _RETENTION_COUNT / _RETENTION_DAYS, or set them all in Settings. |
ACTIVITY_LOG_RETENTION_DAYS |
No | 90 |
Drop audit log rows older than this many days |
JWT_ACCESS_EXPIRY |
No | 15m |
Access token lifetime (jsonwebtoken duration: 15m, 1h, 30s) |
JWT_REFRESH_EXPIRY |
No | 7d |
Refresh token lifetime |
WEBAUTHN_RP_ID |
No | (none) | Registrable domain for passkey sign-in (e.g. mikr.example.com). Must be a real domain, not an IP. |
WEBAUTHN_RP_NAME |
No | MikroTik Manager |
Display name shown by the authenticator during passkey registration |
WEBAUTHN_ORIGINS |
No | (derived from WEBAUTHN_RP_ID) |
Comma-separated list of allowed origins for passkey ceremonies |
DEFAULT_SSH_PORT |
No | 22 |
Pre-filled SSH port for new devices (per-device override always wins) |
DEFAULT_API_PORT |
No | 443 |
Pre-filled REST API port for new devices |
Important: If you rely on auto-generated secrets, back up data/.secrets.json alongside the SQLite database. Losing it invalidates all sessions and makes stored device passwords unrecoverable. ENCRYPTION_KEY must be exactly 64 hex characters — if changed after devices are added, existing encrypted passwords won't decrypt.
| Capability | SSH | REST API | SNMP |
|---|---|---|---|
| Status monitoring | ✓ | ✓ | ✓ |
| CLI commands | ✓ | ✓ | — |
| RouterOS upgrades | ✓ | ✓ | — |
| Config backup | ✓ | ✓ | — |
| Interface details | ✓ | ✓ | ✓ |
| Self-signed TLS | N/A | ✓ | N/A |
| Session overhead | 1 SSH conn | HTTPS per request | UDP per poll |
- SSH — non-interactive exec, best compatibility with all RouterOS versions
- REST API — available on RouterOS 7.1+, supports HTTPS and HTTP
- SNMP — monitoring only (no commands, upgrades, or backups). Useful for devices where SSH/REST isn't available
Devices can use SSH or REST as primary method, with SNMP as an optional supplementary source for faster status checks. The device detail page detects available methods from actual service data and allows quick switching between them — the SSH / REST / SNMP switch stays available in every state, including SNMP-only and offline devices, so you can always change a device's method back (v1.48.2+).
All features are available on every tier — the only difference is the device limit.
| Community | License 30 | License 50 | License Unlimited | |
|---|---|---|---|---|
| Devices | up to 10 | up to 30 | up to 50 | Unlimited |
| Price | €0 | €99 (one-time) | €149 (one-time) | €399 (one-time) |
| Updates | — | €39/year (optional) | €49/year (optional) | €99/year (optional) |
| All features | ✓ | ✓ | ✓ | ✓ |
- Perpetual license — the software works forever on the purchased version
- Update subscription — grants access to new versions (optional, not required)
- Self-hosted — your data stays on your server, offline license activation
- No account required, no telemetry, no usage tracking — none of your fleet/device/config data ever leaves the server
- The only outbound traffic is optional read-only public-feed checks (RouterOS CVE feed from NVD, RouterOS release changelogs and latest version from MikroTik, Manager update from GitHub Releases) — GET-only, carry no data, individually disable-able, and degrade gracefully offline
SQLite database stored in ./data/mikr.db. Persists across container updates.
# Backup
cp data/mikr.db mikr-backup.db
# Restore
cp mikr-backup.db data/mikr.db
docker restart mikr-managerdocker compose logs -f # View logs
docker compose restart # Restart
docker compose down # Stop
docker compose up -d # Start / update- Backend: Node.js 22, Express.js, SQLite (better-sqlite3)
- Frontend: Vanilla JS SPA (no framework), CSS3
- Real-time: WebSocket for live status, command output, upgrade progress
- Auth: JWT + bcrypt, role-based (superadmin / admin / operator / viewer) with per-site scoping
- MikroTik: SSH (node-ssh) + REST API (https module) + SNMP (net-snmp)
- Encryption: AES-256-GCM for stored device passwords
- Container: Docker, node:22-alpine (multi-stage build)