MikroTik RouterOS CHR (Cloud Hosted Router) with QEMU. Use when: running RouterOS in QEMU, booting CHR images, debugging CHR boot failures, setting up VirtIO devices for RouterOS, choosing between SeaBIOS and UEFI boot, configuring QEMU port forwarding for RouterOS REST API, or selecting QEMU acceleration (KVM/HVF/TCG).
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Instruções da origem · Visualização somente leitura
name
routeros-qemu-chr
description
MikroTik RouterOS CHR (Cloud Hosted Router) with QEMU. Use when: running RouterOS in QEMU, booting CHR images, debugging CHR boot failures, setting up VirtIO devices for RouterOS, choosing between SeaBIOS and UEFI boot, configuring QEMU port forwarding for RouterOS REST API, or selecting QEMU acceleration (KVM/HVF/TCG).
RouterOS CHR with QEMU
What Is CHR
Cloud Hosted Router (CHR) is MikroTik's x86_64 and aarch64 RouterOS image designed for virtual machines. Free license allows unlimited use with 1 Mbps speed limit — sufficient for development, testing, API work, and packet sniffer debugging. A free 60-day trial removes the speed limit entirely (requires a free mikrotik.com account). See CHR licensing reference for full details on license tiers, trial activation, and expiry behavior.
Image Variants
Image
Architecture
Boot method
Source
chr-<ver>.img
x86_64
SeaBIOS (MBR chain-load)
download.mikrotik.com
chr-<ver>-arm64.img
aarch64
UEFI (EDK2 pflash)
download.mikrotik.com
chr-efi.img (fat-chr)
x86_64
UEFI (OVMF)
tikoci/fat-chr GitHub
Standard x86 image has a proprietary boot partition — it looks like an EFI System Partition in GPT but is NOT FAT. UEFI firmware (OVMF) cannot read it. Only SeaBIOS can boot it via MBR chain-load.
The fat-chr repackaged image converts this to standard FAT16 with EFI/BOOT/BOOTX64.EFI, enabling UEFI boot. Required for Apple Virtualization.framework on X86 macOS, optional everywhere else.
Pros: Full lifecycle control, parallel instance management, TypeScript-native.
Cons: More code, QEMU args still need to be correct.
Pattern D: Config file (--readconfig) (declarative, used by mikropkl)
QEMU's --readconfig loads an INI-format file for device/machine config. The mikropkl project uses this for its declarative VM packaging.
Tradeoffs: Separates concerns (config vs launch), but the INI format is obscure and not all QEMU options can be expressed in it (pflash, -accel, -netdev user,hostfwd all require command-line args). Best suited for projects that generate configs programmatically.
-M pc (i440fx, legacy PCI) also works for CHR. CHR doesn't exercise most of what q35 adds (modern PCIe topology, ACPI-based hotplug, etc.) because the RouterOS kernel bypasses the BIOS/ACPI stack after boot — the VirtIO PCI devices are what it actually uses, and both machine types expose those identically. For the kernel-config evidence behind this, see tikoci/mikrotik-gpl (v7.2 kernel config archive).
Boot time: ~5s (KVM), ~30s (TCG). For TCG, -accel tcg,tb-size=256 enlarges the translation block cache and reduces boot time noticeably on repeated runs.
aarch64 with UEFI (EDK2)
Requires UEFI pflash firmware files. Both pflash units must be identical size (typically 64 MiB):
On x86_64 q35, if=virtio resolves to PCI — works fine. On aarch64 virt, it resolves to MMIO — RouterOS kernel stalls silently. Always use explicit -device virtio-blk-pci on aarch64:
Key rule: KVM and HVF both require host/guest architecture match. Cross-arch always falls back to TCG. Don't check just for /dev/kvm — verify the architecture matches too.
HVF + CPU Model Gotcha (macOS)
With -accel hvf, QEMU exposes the host CPU directly. Specifying a CPU model like cortex-a710 (ARMv9, requires SVE2) on Apple Silicon (ARMv8.5) crashes QEMU before the VM starts. Use -cpu host with HVF:
Startup race — pitfall if you then call the REST API immediately
RouterOS boot is staged from the client's perspective:
Connection refused — QEMU still booting
ECONNRESET — HTTP server up but REST subsystem not accepting
401 from /rest/* — auth middleware up; REST handler may still be initializing
200 but wrong body — REST initialized before routing tables settled; /system/resource can briefly return an array (e.g., a /user list) before it returns the expected singleton object
200 with correct body — fully operational
A health check on the root / reaches stage 2 but gives no signal about 3–5. For code that will immediately call the REST API, probe /rest/system/resource with auth and require two consecutive successful probes with the expected body shape (singleton object containing board-name). On auth-only checks (unprovisioned admin), accept 401/403 as "REST layer responded." The / + HTTP 200 check is fine for "is it up?" monitoring but not for "can I start calling REST now?"
Port Forwarding
QEMU user-mode networking (-netdev user,hostfwd=...) for typical RouterOS services:
Use unique host ports per instance when running multiple CHRs (9180, 9181, 9182...).
Known Limitations
QGA (Guest Agent) requires KVM — RouterOS CHR's QGA daemon only starts when it
detects a KVM hypervisor via CPUID. Under HVF (macOS) or TCG (software emulation),
CPUID 0x40000000 returns no KVM vendor string and 0x40000001 returns no KVM features,
so the daemon never starts. QEMU correctly provides the virtio-serial port and sends
PORT_OPEN (event 6) — the guest simply never opens it (query-chardev shows
frontend-open=false). This is NOT a QEMU bug. MikroTik documents QGA exclusively
under the "KVM" section. QGA testing requires Linux + KVM (e.g., mikropkl lab).
check-installation fails on aarch64 in all QEMU environments — this is an unresolvable firmware/DTB issue (see known issues)
Direct -kernel boot does not work for either architecture — RouterOS needs its full firmware boot path
Cross-arch TCG: x86_64 on aarch64 host is not viable — x86 I/O port emulation is too slow (~300s+ timeouts). The reverse (aarch64 on x86_64) works fine (~20s)
No virtio_mmio driver — always use explicit -device virtio-blk-pci, never rely on if=virtio on aarch64