Installation Guide

Install MikroTik Manager using Docker, Docker Compose, or as a MikroTik Container App.

Contents
  1. Requirements
  2. Installation (Docker)
  3. Installation (Docker Compose)
  4. MikroTik Container (RouterOS)
  5. Environment Variables
  6. Updating
  7. Activating a License
  8. Enabling HTTPS
  9. Prometheus & Grafana
  10. Troubleshooting

1. Requirements

2. Installation

Step 1 — Pull the image

docker pull ghcr.io/hreskiv/mikr:latest

Step 2 — Create a data directory

This directory stores the SQLite database, TLS certificates, and backups. It persists across container restarts and updates.

mkdir -p /opt/mikr/data

Step 3 — Run the container

docker run -d \
  --name mikr-manager \
  --restart unless-stopped \
  -p 3000:3000 \
  -p 3443:3443 \
  -p 5514:5514/udp \
  -p 5514:5514/tcp \
  -v /opt/mikr/data:/app/data \
  -e STORAGE_ADAPTER=sqlite \
  ghcr.io/hreskiv/mikr:latest

Port 5514 is the optional syslog receiver (Log collector). Both UDP and TCP listeners run by default — RouterOS 7.x can send over either. Skip the -p 5514:5514/... lines if you don't need logs, or set SYSLOG_ENABLED=false / SYSLOG_TCP_ENABLED=false.

Step 4 — Create the admin user

docker exec mikr-manager node scripts/seed.js
Default credentials are admin / admin. Change the password immediately after first login.

Step 5 — Open in browser

Navigate to http://your-server-ip:3000 and log in.

3. Installation (Docker Compose)

If you prefer Docker Compose, create these two files and run one command.

Step 1 — Create project directory

mkdir -p /opt/mikr && cd /opt/mikr

Step 2 — Create .env file

This file stores your secrets. Generate random values and save them — you'll need the same keys on every update.

cat > /opt/mikr/.env <<EOF
JWT_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
EOF
Back up .env immediately. If ENCRYPTION_KEY is lost, all stored device passwords become unreadable.

Step 3 — Create docker-compose.yml

cat > /opt/mikr/docker-compose.yml <<'EOF'
services:
  mikr:
    image: ghcr.io/hreskiv/mikr:latest
    container_name: mikr-manager
    restart: unless-stopped
    ports:
      - "3000:3000"
      - "3443:3443"
      - "5514:5514/udp"       # optional — syslog receiver UDP
      - "5514:5514/tcp"       # optional — syslog receiver TCP
    volumes:
      - ./data:/app/data
    environment:
      - STORAGE_ADAPTER=sqlite
    env_file:
      - path: .env
        required: false
EOF

Step 4 — Start and seed

cd /opt/mikr
docker compose up -d
docker exec mikr-manager node scripts/seed.js
Default credentials are admin / admin. Change the password immediately after first login.

Updating with Docker Compose

cd /opt/mikr
docker compose pull
docker compose up -d
Docker Compose automatically reads .env — your secrets persist across updates without extra flags.

4. MikroTik Container (RouterOS 7.22+)

Run mikr directly on a MikroTik router using the Container feature — no separate server needed.

Requirements

Container App YAML

Paste this into the YAML tab of the MikroTik Container App configuration:

name: mikr
descr: MikroTik Manager — web-based device management, monitoring, and configuration for MikroTik fleets.
page: https://mikr.app
category: networking
default-credentials: admin/admin
services:
  mikr:
    image: ghcr.io/hreskiv/mikr:latest
    ports:
      - "3000:3000:web"
      - "3443:3443:web-ssl"
      - "5514:5514/udp:syslog-udp"
      - "5514:5514/tcp:syslog-tcp"
    environment:
      - HOST=0.0.0.0
      - PORT=3000
      - ENCRYPTION_KEY=<your-encryption-key>
      - JWT_SECRET=<your-jwt-secret>
    volumes:
      - data:/app/data
    restart: unless-stopped
Generate keys with openssl rand -hex 32 before pasting. The admin user is created automatically on first start — no seed command needed.

RouterOS CLI (alternative)

If you prefer configuring via CLI instead of the Container App UI:

# Enable container mode (requires reboot)
/system/device-mode/update container=yes

# Create veth interface for the container
/interface/veth/add name=veth-mikr address=172.17.0.2/24 gateway=172.17.0.1

# Create a bridge for containers
/interface/bridge/add name=bridge-containers
/interface/bridge/port/add bridge=bridge-containers interface=veth-mikr
/ip/address/add address=172.17.0.1/24 interface=bridge-containers

# NAT for container internet access
/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24

# Port forwarding — access mikr from LAN
/ip/firewall/nat/add chain=dstnat action=dst-nat protocol=tcp \
    dst-port=3000 to-addresses=172.17.0.2 to-ports=3000

# (optional) Syslog receiver — lets other MikroTiks send logs to mikr
/ip/firewall/nat/add chain=dstnat action=dst-nat protocol=udp \
    dst-port=5514 to-addresses=172.17.0.2 to-ports=5514
# (optional) TCP syslog — useful when UDP is blocked in the path
/ip/firewall/nat/add chain=dstnat action=dst-nat protocol=tcp \
    dst-port=5514 to-addresses=172.17.0.2 to-ports=5514

# Persistent data mount (use USB/NVMe, not NAND flash)
/container/mounts/add name=mikr-data src=disk1/mikr/data dst=/app/data

# Environment variables
/container/envs/add name=mikr-env key=HOST value=0.0.0.0
/container/envs/add name=mikr-env key=PORT value=3000
/container/envs/add name=mikr-env key=ENCRYPTION_KEY value=<your-key>
/container/envs/add name=mikr-env key=JWT_SECRET value=<your-secret>

# Pull and create container
/container/add remote-image=ghcr.io/hreskiv/mikr:latest \
    interface=veth-mikr envlist=mikr-env mounts=mikr-data \
    hostname=mikr start-on-boot=yes logging=yes

# Start
/container/start 0
Use USB or NVMe storage for the data mount — internal NAND flash has limited write cycles. mikr can monitor the router it runs on via the bridge IP (172.17.0.1).

5. Environment Variables

Pass variables with -e flags or mount an .env file. All are optional with sensible defaults.

VariableDefaultDescription
PORT3000HTTP server port
HTTPS_PORT3443HTTPS server port
JWT_SECRETauto-generatedSecret for JWT tokens. If unset, a random value is generated on first start and persisted to data/.secrets.json.
ENCRYPTION_KEYauto-generated64-char hex key for AES-256-GCM device password encryption. Same auto-generate + persist behavior as JWT_SECRET.
MONITOR_INTERVAL_MS60000Device polling interval in milliseconds
MONITOR_CONCURRENCY10Max devices polled simultaneously
TLS_ENABLEDfalseEnable HTTPS (auto-generates self-signed cert)
TLS_CERT_PATHPath to custom TLS certificate
TLS_KEY_PATHPath to custom TLS private key
METRICS_ENABLEDfalseEnable the /metrics Prometheus endpoint. Disabled by default.
METRICS_TOKENBearer token for /metrics endpoint. Optional but recommended; empty = no auth.
SYSLOG_ENABLEDtrueEnable the UDP syslog receiver (Log collector).
SYSLOG_PORT5514UDP port for the syslog listener.
SYSLOG_TCP_ENABLEDtrueEnable the TCP syslog receiver (parallel to UDP, same port by default). Useful when UDP is blocked.
SYSLOG_TCP_PORT5514TCP port for the syslog listener (defaults to SYSLOG_PORT).
LOG_LEVELinfoLog level: debug, info, warn, error
On first start with no JWT_SECRET / ENCRYPTION_KEY set, the Manager generates strong random values and saves them to data/.secrets.json (mode 0600). Back up this file — losing it invalidates all sessions and makes stored device passwords unrecoverable. To use your own values, set them via env or .env (env always wins); generate with openssl rand -hex 32.

Example with custom secrets:

docker run -d \
  --name mikr-manager \
  --restart unless-stopped \
  -p 3000:3000 \
  -p 3443:3443 \
  -v /opt/mikr/data:/app/data \
  -e STORAGE_ADAPTER=sqlite \
  -e JWT_SECRET=$(openssl rand -hex 32) \
  -e ENCRYPTION_KEY=$(openssl rand -hex 32) \
  ghcr.io/hreskiv/mikr:latest
If you change ENCRYPTION_KEY after adding devices, existing stored passwords become unreadable. Save it securely.

6. Updating

Your data is stored in /opt/mikr/data (mounted volume), so it survives container replacement.

Docker Compose

cd /opt/mikr
docker compose pull
docker compose up -d
Docker Compose automatically reads .env — your secrets persist across updates without extra flags.

Plain Docker

# Pull the latest image
docker pull ghcr.io/hreskiv/mikr:latest

# Stop and remove the old container
docker stop mikr-manager
docker rm mikr-manager

# Start a new container with the same settings
docker run -d \
  --name mikr-manager \
  --restart unless-stopped \
  -p 3000:3000 \
  -p 3443:3443 \
  -v /opt/mikr/data:/app/data \
  --env-file /opt/mikr/.env \
  ghcr.io/hreskiv/mikr:latest
If you used -e flags instead of --env-file, include them again in the docker run command. See Environment Variables for the recommended .env file approach.

Clean up old images

docker image prune -f

7. Activating a License

The Community edition supports up to 10 devices for free. To manage more devices, activate your license key in the app:

  1. Log in as admin
  2. Navigate to License in the sidebar
  3. Paste your license key and click Activate

The license is stored in the database and persists across updates.

8. Enabling HTTPS

Auto-generated self-signed certificate

docker run -d \
  --name mikr-manager \
  --restart unless-stopped \
  -p 3000:3000 \
  -p 3443:3443 \
  -v /opt/mikr/data:/app/data \
  -e STORAGE_ADAPTER=sqlite \
  -e TLS_ENABLED=true \
  ghcr.io/hreskiv/mikr:latest

Access via https://your-server-ip:3443. Your browser will warn about the self-signed cert — this is expected.

Custom certificate

docker run -d \
  --name mikr-manager \
  --restart unless-stopped \
  -p 3000:3000 \
  -p 3443:3443 \
  -v /opt/mikr/data:/app/data \
  -v /path/to/certs:/certs:ro \
  -e STORAGE_ADAPTER=sqlite \
  -e TLS_ENABLED=true \
  -e TLS_CERT_PATH=/certs/fullchain.pem \
  -e TLS_KEY_PATH=/certs/privkey.pem \
  ghcr.io/hreskiv/mikr:latest
Both HTTP (port 3000) and HTTPS (port 3443) run in parallel. WebSocket (WS/WSS) works automatically on both.

9. Prometheus & Grafana

mikr exposes a /metrics endpoint in Prometheus text format. Connect it to Prometheus + Grafana for historical graphs of CPU, memory, temperature, and device availability.

Enable the endpoint

The /metrics endpoint is disabled by default (returns 404). Opt in by setting METRICS_ENABLED=true:

# In .env file
METRICS_ENABLED=true
# Optional but recommended — Bearer token auth
METRICS_TOKEN=your-secret-token

Generate a strong random token:

openssl rand -hex 32

If METRICS_TOKEN is set, Prometheus must send a Bearer token or use ?token=your-secret-token.

Verify metrics are available

curl http://your-server-ip:3000/metrics

Prometheus configuration

Add this to your prometheus.yml:

scrape_configs:
  - job_name: 'mikr'
    scrape_interval: 60s
    metrics_path: /metrics
    static_configs:
      - targets: ['your-server-ip:3000']

With token authentication:

scrape_configs:
  - job_name: 'mikr'
    scrape_interval: 60s
    metrics_path: /metrics
    authorization:
      type: Bearer
      credentials: 'your-secret-token'
    static_configs:
      - targets: ['your-server-ip:3000']

If mikr uses HTTPS (port 3443):

scrape_configs:
  - job_name: 'mikr'
    scheme: https
    tls_config:
      insecure_skip_verify: true
    scrape_interval: 60s
    metrics_path: /metrics
    static_configs:
      - targets: ['your-server-ip:3443']

Available metrics

MetricDescription
mikr_device_upDevice reachability (1 = online, 0 = offline)
mikr_device_cpu_percentCPU load percentage
mikr_device_memory_percentMemory usage percentage
mikr_device_memory_free_bytesFree memory in bytes
mikr_device_memory_total_bytesTotal memory in bytes
mikr_device_uptime_secondsDevice uptime in seconds
mikr_device_temperature_celsiusBoard temperature
mikr_device_voltage_voltsInput voltage
mikr_device_power_wattsPower consumption
mikr_device_infoDevice metadata (RouterOS version, model, architecture)
mikr_devices_totalTotal number of enabled devices
mikr_devices_onlineNumber of online devices

All per-device metrics include labels: name, host, site.

Grafana dashboard

Import the ready-made dashboard template:

  1. Download grafana-dashboard.json
  2. In Grafana, go to Dashboards → Import → Upload JSON file
  3. Select your Prometheus data source and click Import

The dashboard includes: fleet overview stats, device status table, CPU/memory time series, temperature/voltage/power graphs, uptime tracking, RouterOS version distribution, and device model breakdown. Filter by site and device using the dropdown variables at the top.

mikr polls devices every 60 seconds. Set Prometheus scrape_interval to 60s to match — scraping more frequently won't provide additional data.

10. Troubleshooting

View logs

docker logs mikr-manager --tail 100

Follow logs in real-time

docker logs mikr-manager -f

Enable debug logging

Stop the container and re-run with -e LOG_LEVEL=debug to see SSH/REST connection details.

Container won't start

Devices show "Error" or "Offline"

Reset admin password

If you lost access, re-run the seed script. It only creates a new admin if none exists. To force reset, access the SQLite database directly:

docker exec -it mikr-manager sh
node -e "
const {getStore}=require('./src/data/store');
const {hashPassword}=require('./src/services/auth.service');
(async()=>{
  const store=getStore();
  const hash=await hashPassword('newpassword');
  store.db.prepare('UPDATE users SET password_hash=? WHERE username=?').run(hash,'admin');
  console.log('Password reset to: newpassword');
})();"