hossein3piol/mikrotik-routeros

By hossein3piol

Updated about 1 month ago

Run MikroTik RouterOS CHR inside Docker using QEMU with multi-architecture support.

Image
Networking
Security
Operating systems
2

2.1K

hossein3piol/mikrotik-routeros repository overview

MikroTik RouterOS on Docker

Docker Image Docker Pulls GitHub Stars License: MIT

A production-ready, QEMU-powered environment for running MikroTik RouterOS CHR inside Docker — on any architecture, without sacrificing your host OS.


Overview

This project packages MikroTik RouterOS (Cloud Hosted Router) inside a Docker container using QEMU for full x86_64 virtualization. It is designed for infrastructure engineers who need a reproducible, version-controlled MikroTik environment on any Linux server — with complete persistence, host file sharing, and safe port routing.

Because QEMU handles the x86_64 emulation layer, the Docker image itself is built for multiple CPU architectures. Whether your host is an AMD64 server, an ARM64 Raspberry Pi, or any other supported platform, you can pull and run the same image without any modifications.


Features

FeatureDescription
Multi-ArchitecturePre-built for amd64, arm64, arm/v7, arm/v6, and 386
Persistent StorageRouter configuration survives container rebuilds via a host-mounted virtual drive
Host ↔ Guest File SharingA local directory is exposed inside MikroTik's File Manager as a virtual FAT drive
Safe SSH AccessMikroTik SSH is remapped to port 2222 — your host SSH on port 22 is untouched
Dynamic Port RangePorts 9000–9100 are pre-allocated for custom services — no Compose restarts needed
Version PinningSwitch RouterOS versions via a single environment variable
KVM AccelerationHardware virtualization is enabled automatically when /dev/kvm is available, with graceful fallback to software emulation
Graceful ShutdownSIGTERM is caught and forwarded to QEMU — MikroTik shuts down cleanly on docker compose down

Prerequisites

  • Linux host with Docker Engine installed
  • Docker Compose v2+
  • KVM support recommended (/dev/kvm available) for acceptable performance

Note: KVM is optional. If unavailable, QEMU falls back to software emulation automatically. Performance will be lower but the router will function correctly.


Supported Architectures

ArchitectureTag
x86-64linux/amd64
ARM 64-bitlinux/arm64
ARM 32-bit v7linux/arm/v7
ARM 32-bit v6linux/arm/v6
x86 32-bitlinux/386

Docker will automatically pull the correct variant for your host platform.


Quick Start

1. Clone the repository
git clone https://github.com/im-ecorp/mikrotik-routeros.git
cd mikrotik-routeros
2. Configure environment variables

Copy the example and set your desired RouterOS version:

cp .env.example .env
# Edit .env and set ROUTEROS_VERSION and optionally TZ

.env example:

ROUTEROS_VERSION=7.22.2
TZ=Asia/Tehran

If .env is omitted, the latest tag and Asia/Tehran timezone are used by default.

3. Start the container
docker compose up -d
4. Connect to MikroTik
MethodAddress
Winbox<server-ip>:8291
SSHssh admin@<server-ip> -p 2222
WebFighttp://<server-ip>:80
API<server-ip>:8728

Default credentials: admin / (no password — set one immediately)


Architecture

How It Works
┌──────────────────────────────────────────────────────┐
│  Docker Container (Alpine Linux)                     │
│                                                      │
│   ┌────────────────────────────────────┐             │
│   │  QEMU (x86_64 system emulation)    │             │
│   │                                    │             │
│   │   MikroTik RouterOS CHR            │             │
│   │   ├── chr.vdi  (persistent disk)   │             │
│   │   └── FAT drive (./shared)         │             │
│   └────────────────┬───────────────────┘             │
│                    │ TAP / bridge (qemubr0)           │
└────────────────────┼─────────────────────────────────┘
                     │
              Docker bridge network
              172.24.0.0/16

Regardless of the host CPU architecture, QEMU always emulates an x86_64 machine for MikroTik — this is why the image runs identically on ARM and AMD64 hosts.

Directory Structure
.
├── bin/
│   ├── entrypoint.sh          # Container entrypoint & QEMU launcher
│   ├── generate-dhcpd-conf.py # Dynamic DHCP config generator
│   ├── qemu-ifup              # TAP interface bring-up script
│   └── qemu-ifdown            # TAP interface teardown script
├── data/                      # Auto-created — stores chr.vdi (persistent)
├── shared/                    # Auto-created — shared with MikroTik File Manager
├── .github/
│   └── workflows/
│       └── docker-image.yml   # CI/CD pipeline for building & publishing images
├── Dockerfile
├── docker-compose.yml
└── .env.example
Volumes
Host PathContainer PathPurpose
./data/routeros/dataStores the persistent virtual hard drive (chr.vdi)
./shared/routeros/sharedExposed to MikroTik as a virtual FAT drive

Important: Never delete ./data unless you intend to reset the router to factory defaults. Never run docker compose down -v.


Port Reference

PortProtocolService
21TCPFTP
22 → host 2222TCPSSH (remapped)
23TCPTelnet
80TCPWebFig (HTTP)
443TCPWebFig (HTTPS)
1194TCP/UDPOpenVPN
1701UDPL2TP
1723TCPPPTP
8291TCPWinbox
8728TCPRouterOS API
8729TCPRouterOS API-SSL
13231UDPWireGuard
9000–9100TCPReserved for custom services

Tip: If you need to reassign a default MikroTik service port, use any port in the 9000–9100 range — it will be immediately reachable without modifying docker-compose.yml.


Configuration

Changing the RouterOS Version

Update ROUTEROS_VERSION in your .env file, then recreate the container:

docker compose down
docker compose up -d

The existing chr.vdi in ./data will be reused. To start fresh with the new version's default config, delete ./data/chr-*.vdi before starting.

Changing the Timezone
TZ=Europe/Berlin
Stopping the Container
docker compose down

Your configuration is safely stored in ./data and will persist for the next startup.


CI/CD: Building and Publishing Images

A GitHub Actions workflow is included at .github/workflows/docker-image.yml. It builds a multi-architecture image and pushes it to both Docker Hub and GitHub Container Registry (GHCR).

Required Secrets

Configure these under Settings → Secrets and variables → Actions:

SecretDescription
DOCKERHUB_USERNAMEYour Docker Hub username
DOCKERHUB_TOKENDocker Hub access token
CR_PATGitHub Personal Access Token with write:packages scope
Triggering a Build
  1. Go to Actions → Build and Push MikroTik Image
  2. Click Run workflow
  3. Fill in the inputs:
InputDescription
versionRouterOS version to build (e.g. 7.22.2)
tag_latestCheck to also push the latest tag for this version
Published Tags

Each build produces the following tags (both with and without the v prefix for maximum compatibility):

hossein3piol/mikrotik-routeros:7.22.2
hossein3piol/mikrotik-routeros:v7.22.2
ghcr.io/im-ecorp/mikrotik-routeros:7.22.2
ghcr.io/im-ecorp/mikrotik-routeros:v7.22.2

# If "tag_latest" was checked:
hossein3piol/mikrotik-routeros:latest
ghcr.io/im-ecorp/mikrotik-routeros:latest
Building Manually on Your Server
docker build \
  --build-arg ROUTEROS_VERSION=7.22.2 \
  -t hossein3piol/mikrotik-routeros:v7.22.2 \
  -t hossein3piol/mikrotik-routeros:7.22.2 \
  .

docker push hossein3piol/mikrotik-routeros:v7.22.2
docker push hossein3piol/mikrotik-routeros:7.22.2

Advanced: OpenVPN Configuration

Click to expand — step-by-step OpenVPN setup guide
1. IP Pool Setup

Add a private IP range for VPN clients under IP → Pool. For example: 172.24.0.0/16

ip_pool

2. Generate Certificates

Create or import the required certificates under System → Certificates.

certificate

3. Create an OpenVPN Profile

Configure the PPP Profile under PPP → Profiles with the appropriate local and remote address settings.

profile

4. Add Client Secrets

Define user credentials under PPP → Secrets.

client

5. Configure the OpenVPN Interface

Create an OpenVPN Server interface under Interfaces → OpenVPN Server. The example below uses port 4646 instead of the default 1194.

interface

6. Configure NAT Masquerade

This step is critical for client internet access. Add a masquerade rule under IP → Firewall → NAT.

firewall_nat


Troubleshooting

Container exits immediately

  • Verify KVM is available: ls -la /dev/kvm
  • Check logs: docker compose logs -f
  • If KVM is unavailable, the container will fall back to software emulation automatically

Cannot connect via Winbox

  • Confirm the container is running: docker compose ps
  • The healthcheck polls port 8291 — wait until status shows healthy

MikroTik lost its configuration after restart

  • Ensure ./data directory exists and is writable by the container
  • Never use docker compose down -v

SSH connection refused

  • MikroTik SSH is on port 2222, not 22
  • Connect with: ssh admin@<server-ip> -p 2222

Bridge already exists error on restart

  • The entrypoint checks for an existing bridge before creating one — this is handled automatically

Acknowledgments

  • lordbasex — original inspiration for the QEMU-in-Docker approach

Support

If this project saves you time in your infrastructure work, consider supporting its development:

  • USDT (TRC20): TH1iDsFr2wjgpptghFBn6h7DVt88pp5WoH

Stargazers over time

Tag summary

Content type

Image

Digest

sha256:ed2a53949

Size

88.5 MB

Last updated

about 1 month ago

docker pull hossein3piol/mikrotik-routeros