docker-routeros runs a MikroTik RouterOS VM inside QEMU in a container
This project provides a Docker image that runs a MikroTik RouterOS virtual machine inside QEMU.
At a glance
- What is it?
- docker-routeros is a Docker image that boots the MikroTik RouterOS Cloud Hosted Router as a QEMU virtual machine, so developers can test against a real RouterOS API without hardware. It is built for linux/amd64 and linux/arm64, it publishes moving tags for every stable release, and the README is explicit that it is a simulation tool rather than a production deployment.
- Who is it for?
- docker-routeros suits a developer writing against the RouterOS API who needs a reproducible RouterOS instance in CI or on a laptop, since the image pins a RouterOS version, publishes the API ports and can be joined to other containers on a shared network.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 25 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the image is and what it is for
This project provides a Docker image that runs a MikroTik RouterOS virtual machine inside QEMU.
The RouterOS inside the container is the real thing, not a reimplementation. The Dockerfile downloads the Cloud Hosted Router disk image from MikroTik's own CDN, with the URL built from the version argument, and that image is what QEMU boots. That distinction is the whole value of the project: the API you write against is the API of an actual RouterOS, with its actual command set, its actual quirks and its actual versioning behaviour.
The intended use is stated plainly. It is designed to simulate a MikroTik RouterOS environment and is useful for development and testing, especially when working with the RouterOS API.
And the README names the concrete case it was built for: the image is well-suited for unit testing the routeros-api-php library in a controlled environment that closely mimics a real RouterOS setup. That is the same author's own API library, so this is a test dependency for a library that needs a RouterOS to talk to.
The README is equally clear about the limits of the approach. For a production-ready RouterOS environment in Docker, it points at the VR Network Lab project as an alternative. That distinction is worth taking seriously, because a QEMU virtual machine with host port forwarding is a simulation of a router, not a router, and the networking behaviour differs in ways that matter for production.
The project is MIT licensed, the primary language is Shell, and the last push was on 2026-09-28.
Pulling and running the image
The quick start is two commands, and the ports are the thing to look at.
docker pull evilfreelancer/docker-routeros
docker run -d -p 2222:22 -p 2223:23 -p 8728:8728 -p 8729:8729 -p 5900:5900 -ti evilfreelancer/docker-routerosThe port list maps the guest's services onto different host ports so that you can run more than one instance without collisions: 2222 to SSH on 22, 2223 to telnet on 23, 8728 and 8729 to the API ports, and 5900 to VNC. The API ports are the reason most people come here, since the RouterOS API is what you are testing against.
The README notes that you can optionally pin to a RouterOS version tag from the Docker Hub tags page, which matters for CI, where a moving tag means the thing under test changes without anyone changing the code.
Then the wait, which trips people up. Wait 30-60 seconds after start for RouterOS to boot, then connect, for example with ssh -p 2222 admin@localhost or telnet localhost 2223.
That delay is the boot time of a real operating system inside a virtual machine, and it is not something the container can avoid, because the guest is a full RouterOS installation rather than a process emulating its API. A test that starts the container and immediately connects will fail, and the fix is in the wait, not in the code.
The image is published for linux/amd64 and linux/arm64, and on Apple Silicon the M1, M2 and M3, Docker pulls the arm64 image automatically. The caveat is stated in the same paragraph: RouterOS CHR is x86_64 only, so on arm64 the image runs RouterOS inside QEMU emulation with no KVM on Mac and ARM, and it may be slower than on amd64 with KVM.
Why two networks, and how the ports work
The networking section is the most technical part of the README, and it exists because the simple single-network arrangement has a real problem.
The recommended setup is two networks, so that host port mapping works reliably while the RouterOS guest is on a shared network with other containers. The compose file to copy is docker-compose.dist.yml.
services:
routeros:
image: evilfreelancer/docker-routeros:latest
restart: unless-stopped
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun
- /dev/kvm # omit on Apple Silicon (no KVM there; container uses QEMU emulation)
ports:
- "2222:22"
- "2223:23"
- "8728:8728"
- "8729:8729"
volumes:
- ./routeros_data:/data
networks:
- default
- routeros_net
networks:
routeros_net:
driver: bridgeThe mechanics are worth following. With two networks the container gets eth0 on the default network and eth1 on routeros_net. The entrypoint deliberately leaves eth0 for host port mapping, because QEMU forwards ports into the guest using user-mode networking with hostfwd, and puts eth1 in a bridge so the VM gets an IP on routeros_net through DHCP and can reach other containers.
In the single network case the container has only one interface, eth0, and that is put in the bridge, so the VM gets the container IP via DHCP. Inter-container communication then works, but host port mapping relies on the bridge forwarding to the VM, and the README says to prefer two networks for reliable host access because SSH and telnet can hang.
The other requirements in that compose file are not decoration either. The NET_ADMIN capability and the /dev/net/tun device are what the QEMU tap networking needs, and /dev/kvm is the hardware acceleration device, which is omitted on Apple Silicon because there is no KVM there.
For two or more RouterOS instances on the same network, each container needs a unique MAC. By default a unique MAC is generated per volume and stored in ROUTEROS_DATA_DIR/nic_mac, so the fix is to use different volumes per service, and you can set one explicitly with ROUTEROS_NIC_MAC or by writing it to nic_mac in the data dir.
The second example in the README shows exactly that arrangement, with routeros and routeros2 on the same network, different host port ranges, and separate volumes, and from inside either guest you can reach the other by service name.
Building your own image and a specific RouterOS version
The image is not fixed to one RouterOS release, and the build argument is how you choose.
git clone https://github.com/EvilFreelancer/docker-routeros.git
cd docker-routeros
docker build --build-arg ROUTEROS_VERSION=7.16 --tag ros .
docker run -d -p 2222:22 -p 8728:8728 -p 8729:8729 -p 5900:5900 -ti rosYou replace 7.16 with the desired RouterOS version from the MikroTik download archive. The Dockerfile shows how the argument flows through: the ARG ROUTEROS_VERSION becomes the ENV of the same name, the image name is composed as chr-${ROUTEROS_VERSION}.vdi, and the download URL is built from the version and the CDN path. The VDI is then fetched with wget and unzipped in the build.
The base image is alpine:3.24.2, and the package list shows what the runtime needs: netcat-openbsd, qemu-x86_64 and qemu-system-x86_64, busybox-extras, iproute2, iputils, bridge-utils, iptables, jq, bash and python3. The comment about qemu-system-x86_64 is the multi-architecture point again, that it works on both amd64 and arm64 for an x86_64 guest.
Layering your own scripts on top is a short Dockerfile:
FROM evilfreelancer/docker-routeros
ADD ["your-scripts.sh", "/"]
RUN /your-scripts.shThat is the extension point for anything the image does not do, such as provisioning configuration into the guest at boot, and the Dockerfile exposes a wide set of RouterOS ports including 21, 22, 23, 80, 443, 8291, 8728, 8729 and 8900 alongside the IPsec ports.
For a multi-architecture build, buildx is the tool:
docker buildx create --use --name routeros_builder
docker buildx build --platform linux/amd64,linux/arm64 --build-arg ROUTEROS_VERSION=7.16 --tag ros .How the tags are published
The publishing story explains the tag list you see on Docker Hub, and it is the part of this project that does the most work for its users.
GitHub Actions runs on a schedule and on manual trigger. Only stable releases are considered, with RC, alpha and beta ignored. The workflow then:
1. Reads the latest stable RouterOS version from the MikroTik download archive, for example 7.16.1. 2. Fetches all existing tags for this image from Docker Hub, with pagination. 3. If that exact version is missing on Docker Hub, builds the image for linux/amd64 and linux/arm64, then pushes tags for 7.16.1 as the exact version, 7.16 as major.minor, 7 as major, and latest. 4. If that version already exists, updates the moving tags so that 7.16, 7 and latest point to this image, with no rebuild.
The result is stated in one line: latest and major or major.minor tags always follow the newest stable RouterOS.
The distinction between the exact tag and the moving tags is the useful part for anyone writing tests. The exact tag 7.16.1 is immutable in practice and is the one to pin in CI, because it guarantees both the RouterOS version and the image contents. The moving tags are for interactive use, where you want the current stable release without looking up a version number.
The design also has an efficiency property that matters at the maintainer's scale. Once a version's image exists, the workflow does not rebuild it, it only re-points the moving tags. So a new RouterOS release costs one build per architecture, and every subsequent run is a metadata update.
There are no GitHub releases in this repository, so the image tags on Docker Hub are the version record, and the homepage of the project is the Docker Hub page rather than a site of its own.
Where docker-routeros fits, and where it stops
The comparison worth making is with VR Network Lab, which the README itself nominates, and with real hardware.
Against VR Network Lab, the difference is that VR Network Lab is built for network emulation, where you describe a topology of routers and links and it brings the whole thing up, while this project gives you one RouterOS guest in one container. For a test that needs one RouterOS instance to talk to, one container is simpler and lighter. For a test that needs three routers in a mesh with specific addressing between them, you would be assembling that topology yourself out of separate containers and a shared network, which is exactly what the two-network example in the README begins to show.
Against real hardware, the difference is obvious but worth stating in the direction that matters. A container is reproducible, disposable and free, so a CI job can spin one up per test run. It is also not the hardware, so anything that depends on the specific behaviour of a physical CCR or a real radio, or on the performance of the routing stack under real load, tells you nothing when tested here.
The limits are specific. It is a QEMU virtual machine inside a container, so it inherits the boot delay, the emulation overhead and the memory cost of that arrangement. On arm64 there is no KVM, so the guest runs under emulation and the README warns it may be slower. The container needs NET_ADMIN and access to /dev/net/tun, which means it does not run under a restrictive sandbox or a rootless setup without extra work. And the published images follow the newest stable RouterOS under moving tags, so anything that pins latest will see the guest's behaviour change underneath it.
For a developer who needs a RouterOS to point a test at, the image removes the two things that usually block that: acquiring a RouterOS licence image and configuring a machine to run it. The routing configuration is a real RouterOS, so the API behaves as it would in production, and the ports make it reachable from the host and from neighbouring containers.
The last push was on 2026-09-28 and the repository is not archived, and the MIT licence means the image can be rebuilt and modified without restriction.
Editorial conclusion
docker-routeros suits a developer writing against the RouterOS API who needs a reproducible RouterOS instance in CI or on a laptop, since the image pins a RouterOS version, publishes the API ports and can be joined to other containers on a shared network. It is the wrong tool for production, and the README says so, pointing to VR Network Lab for a production-ready RouterOS environment in Docker, and it is the wrong tool if you need full network emulation, since this is a single guest rather than a topology. Before you build, read the networking modes section, because the single network arrangement makes host access unreliable and the two network arrangement is what the README recommends.
Frequently asked questions
What does the docker-routeros image run?
It runs a MikroTik RouterOS virtual machine inside QEMU. The Dockerfile downloads the Cloud Hosted Router VDI image from MikroTik's CDN using the ROUTEROS_VERSION build argument and boots it, so the API you test against is a real RouterOS rather than a reimplementation.
How do I run docker-routeros and connect to it?
Run docker run -d with the ports mapped: 2222 to SSH, 2223 to telnet, 8728 and 8729 to the API and 5900 to VNC. Wait 30 to 60 seconds after start for RouterOS to boot, then connect with ssh -p 2222 admin@localhost or telnet localhost 2223.
Why does the compose file use two networks?
Two networks make host port mapping reliable while putting the guest on a shared network with other containers. The entrypoint leaves eth0 for QEMU user-mode networking with hostfwd so SSH, telnet, API and Winbox work from the host, and bridges eth1 with the VM TAP so the guest gets a DHCP address on routeros_net. With only one network, host access relies on bridge forwarding and can hang.
How do I run two RouterOS instances on the same network?
Each container needs a unique MAC. A unique MAC is generated per volume and stored in ROUTEROS_DATA_DIR/nic_mac, so use a different volume for each service, or set the MAC explicitly with ROUTEROS_NIC_MAC or by writing it to nic_mac in the data directory. The README example shows two services with separate volumes and different host port ranges.
How do the Docker image tags work?
GitHub Actions runs on a schedule and on manual trigger, reads the latest stable RouterOS version from the MikroTik archive, and pushes an exact version tag, a major.minor tag, a major tag and latest. If the exact version image already exists it only re-points the moving tags without rebuilding, so latest and the major tags always follow the newest stable RouterOS.
Can I use docker-routeros in production?
The README says no, and points to the VR Network Lab project as an alternative for a production-ready RouterOS environment in Docker. This image is intended to simulate a RouterOS environment for development and testing, and it is not a network emulation topology tool.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/evilfreelancer-docker-routeros)Was this useful?