MikroTik Solutions

Run NetInstall in a VM
Login

Run NetInstall in a VM

Motivation

The official docs advocate for a complicated and brittle process that arm-twists Windows into the needed role, prominently featuring a sequence of fourteen color glossy screenshots with circles and arrows and a paragraph on the bottom of each one.

While much of that advice is there to undo Windows design decisions that Microsoft cannot change at this late stage,1 a good bit applies equally to OSes that don’t come from Redmond. The fact is that the needs of the world’s computer users have become too diverse to expect a general-purpose OS to suit all these purposes at once and also cater to the idiosyncratic purposes of NetInstall. Something has to give in the name of broad conformity.

In this article, I am not telling you to switch to Linux for your daily driver, nor am I telling those of you who have chosen that path to run netinstall-cli directly on that daily driver. The VM path is superior for everyone because it simplifies the networking tremendously, side-stepping much of the complexity in the official advice. If you follow my path, you will not need to:

The Value of VMs

NetInstall needs to force I/O through a single network path under all conditions in order to do what it does. This might seem like an easy thing to accomplish, but then realize that NetInstall operates at a very low level, and there are multiple stages to the conversation, each of which may have different rules applied by elements of the intervening network.

Once upon a time, a typical computer would have only one “real” network interface plus the loopback interface, giving the OS running NetInstall only one logical choice for all outbound I/O, but modern systems are far more complicated. The one I’m typing this on has twenty-five network interfaces defined. While most of them are virtualized interfaces of some type,6 each one is capable of changing the host OS’s routing table, affecting packet flow. Anyone who thinks they know all the routing rules on such a system without careful inspection and testing is likely wrong.

VMs give us a way to return to those good old days without affecting the host system: configure this NetInstall VM with a single virtual network interface, then bridge that to a specific hardware interface out on the host.

One may then ask, “Doesn’t doing so add a layer of complexity, making the problem worse?” That would be true if we were using shared/NAT networking for this VM, but we aren’t. We’re bridging our lone internal network interface to a single physical interface out on the host, completely bypassing the host’s TCP/IP network stack, forcing all NetInstall traffic down a single path.

Setting up this subordinate VM takes less time than following MikroTik’s advice, which we may distill as:

  1. Completely reconfigure your host machine’s networking to suit NetInstall’s idiosyncrasies.
  2. Attempt the installation, debugging as necessary to work out which of the 14 critical steps you missed.
  3. Revert all that so you can get back to whatever it was you were doing before the need to do the NetInstall came on you.

That last is a critical point: unless you can dedicate a machine to NetInstall, you roughly double the number of steps. Worse, you must redo them each time you need to NetInstall a RouterOS box.

Seen in this context, setting up a VM for this single purpose is cheap, fast, and easy. The idiosyncratic configuration ends up isolated to that one VM.

OS Compatibility

The current version of this guide uses the slimmed-down Alpine Linux as a base. You may be familiar with this as a common base for Linux containers, but it also has an ISO we can install into a VM.

The easy path is:

  1. Download the ISO.

  2. Provision the VM in your hypervisor of choice.

    We need little in the way of resources here. You can dial the VM down to a single CPU core and a gig of disk space. The sole critical element is to bridge the Ethernet connection to the RouterOS device you wish to NetInstall. For VMtek on macOS, it looks like this:

    VMtek Alpine Linux Provisioning

  3. Boot the VM and install the OS.

    The basic installation process works fine for this purpose. You need not get clever here. The complete sequence is:

    localhost login: root
    localhost:~# setup-alpine
    Enter, Enter, Enter, Enter, Enter works, but feel free to customize the install as desired.
    New password: whateverYouLike
    Retype password: whateverYouLike
    Enter, Enter, Enter
    APK Mirror: select the “c” option to enable the “community” repo7
    Enter, Enter, Enter, Enter
    Disk & Install: vda
    How would you like to use it? sys
    WARNING: Erase the above disk(s) and continue? (y/n) [n]: y

    It will take about a minute to do the installation, and then you should then be told, “Installation is complete. Please reboot.” Type reboot and hit Enter.

    If you got some other output, you may need to make alternate selections through the installation. In my case, I needed to reconfigure the virtual CD-ROM in the VM from the default Virtio driver to USB Mass Storage since the installer assumes this is a physical machine installation with the ISO flashed to a USB drive.

  4. Install this article’s support tooling.

    Log in as root using the password you gave the installer above, then:

    # apk update
    # apk add fossil
    # fossil clone https://tangentsoft.com/mikrotik
    

    That last gets you a complete copy of this very web site, including a copy of this article, its support tooling, and more.

    You may wonder why I bother with having you clone this repo rather than just have you download the pieces you need from this web site, onesy-twosy. The glib reason is that it’s quicker and easier this way, but the real reason is that you might need to run this NetInstall process against a border Internet gateway and find yourself needing to load this article back up while knocked offline. It’s easiest to do this with a GUI version of Linux where you can simply say fossil ui from within the repo’s checkout directory to pull up a copy of this very site in the local web browser.

    The closest equivalent on the Alpine console is:

    # cd ~/mikrotik/netinstall
    # fossil wiki export 'Run NetInstall in a VM' | less
    

    Regardless, this principle also explains why this article’s update tool does not clean up after itself. It leaves old versions of the NPKs and scripts behind on purpose, because you may well need to revert to a prior known-working version in an emergency.

If you have cause to disregard the above advice, you’re on your own, but there is no reason to despair if it does not initially work. This article’s principles apply to any Linux flavor; it is simply up to you to apply them correctly. There are two primary areas of difference when choosing a different OS type for your VM: the package manager and the firewall.

Package Manager

The above process uses Alpine Linux in the interests of a small and low-complexity VM, but you can do essentially the same thing atop many different Linux distros. A mainstream distribution like Fedora Workstation will give an easier yet more complete installation, including a modern GUI desktop, at a cost of a heavier VM. Just next-next-next through the installer. The main change here is that the apk commands above become:

$ sudo dnf install fossil

If by chance your Linux of choice for this project lacks a binary package for Fossil, there are statically-linked binaries available for download.

Avoiding the Firewall

Those who chose to use Alpine Linux as their base can skip to the next section because it doesn’t have a default firewall.

Contrast this article’s backup option of Fedora Workstation, which ships with all the ports netinstall-cli needs when communicating with the router blocked by default. Worse, the minimum set of ports isn’t documented anywhere, that I can see. The commands to unblock the required ports are:

sudo firewall-cmd --permanent --add-port bootps/udp
sudo firewall-cmd --permanent --add-port tftp/udp
sudo firewall-cmd --permanent --add-port 5000/udp
sudo firewall-cmd --reload

The first two required ports aren’t much of a surprise given the mention of “BOOTP” in the official docs.

The third isn’t strictly required on Fedora Workstation because its stock firewall includes a rule that supersedes it. It is, however, needed on its enterprise-grade family-mates, which block everything by default except a few key services.

If you find yourself getting stuck at the “sendFile” step, it may be that you failed to unblock port 5000, but beware that there is another possibility: attempting to send packages of the wrong architecture, such as AMD64 to a 32-bit ARM box or vice versa.8

While these commands are particular to Red Hattish OSes, it not because firewalld is proprietary to Red Hat; it is because Linux people love to be fractious and indulge the NIH syndrome. You might therefore need to translate the calls into something functionally equivalent, as on Ubuntu with their ufw system. Other Linuxes may require raw iptables or nft commands.

Or, avoid all this by taking this article’s advice and using Alpine.

Hypervisor Compatibility

The initial version of this article was proven out atop Parallels on macOS, but I do not believe that to be essential to success. Any decent hypervisor should work. The only critical element is that it allow you to bridge the virtual network adapter to the one-and-only host-side Ethernet adapter that netinstall-cli will communicate over.

In Parallels, you do that via the Devices → Network → Bridged Network → Ethernet menu choice. I’ve since switched to VMtek, configured per the screenshot above. The same essential option exists in many other hypervisors, including VMWare, VirtualBox, Linux’s KVM, Apple’s Hypervisor via UTM… Success lies in avoiding cleverness like NAT, “shared” networking, automatic switching between Ethernet and WiFi, etc.

The only common hypervisor I’m aware of which is iffy on this point is Hyper-V, and that’s because while it does have a bridging feature, I’ve experienced multiple repeatable problems with the VM interfering with the host OS, or vice versa. The whole point of doing this is to bypass the network stack of the host OS. Any hypervisor that cannot do this reliably it is liable to cause you more pain than it solves.

Router Configuration

Only one Ethernet port on your router will participate in an EtherBoot conversation. It might be marked “BOOT,” but if not, it’s generally the one that comes up as “ether1” in the default configuration. NetInstall will get stuck in the “Waiting for RouterBOARD...” step if you have the Ethernet cable plugged into the wrong port.

Intervening Hardware

Another common way to fail with NetInstall is to put too much cleverness between the netinstall-cli host and the target device.

The ideal setup is to run a single cable from the netinstall-cli VM’s hardware port to the target’s Etherboot port. Nearly all hosts support Auto MDI-X these days, including MikroTik’s offerings.

Next-simplest is to interpose a dumb Ethernet switch.

Where you start to run risks is when you want to leave one or more smart switches between the VM host and the target device. A common way to fail here is to have a switch supporting DHCP Snooping in the way, which will (not might, will) break NetInstall. If the intervening switch is a MikroTik and you cannot go with one of the two options above, you need to mark the bridge port toward the VM host as “Trusted” to permit passing its BOOTP replies to the target device.

Never interpose anything still smarter, such as a router or a wireless AP. It’s doubtless possible to make it work, but you’re reading this guide to learn the easy path, right? Right.

Do It!

Now that everything is set up properly, we can begin. The easy path is to use the wrapper scripts I have provided, which you cloned down to your NetInstall VM per the instructions above. That then allows you to say things like this:

$ cd ~/mikrotik/netinstall
$ vi doit.in                    # adjust stock template to suit
$ ./update 7.19.4 arm64
$ 7.19.4/arm64/doit

The heathens among you who believe it is poor advice to recommend use of Busybox vi are welcome to go your own way. 🤓

Your choice of text editor aside, the only way to avoid editing this template is if your needs happen to match the use case provided as the single example. Since it doesn’t suffice even for all of my purposes, I expect the chance of it covering every one of your use cases is far too small to count on. The items most likely needing local customization are:

That done, the ./update command above will pull the latest version of netinstall-cli and all the NPKs for the RouterOS version named, then generates a “doit” script from that possibly-customized template.9

The final command above fires that possibly-customized wrapper up. Note that you do not need to cd into the directory first; it handles that for you.

Isn’t This All Rather Over-Complicated?

It may seem so until you come to a few key realizations:

  1. It is useful to have canned configurations for different scenarios, then reapply each as many times as you need to. The proper setup for your core network switch is not the one you want for your APs, nor for your border gateway router. Therefore, once you get a particular configuration working, it may be smart to archive it for later use:

    $ mv 7.19.4/arm64 rb5009-gw-config-2025.08.29
    

    Now you can reapply that configuration by logical name:

    $ rb5009-gw-config-2025.08.29/doit
    
  2. RouterOS upgrades do not always succeed.

    Having a few known-working netinstall-cli commands ready at hand can ease the stress if the upgrade fails. The wrong time to work out the correct command is when you’ve roached the Internet gateway, and now you’re forced to use your smartphone on LTE to search the web for emergency help. Not only is it a pain to copy-paste command text between a phone and the machine you’re using to rescue the router, anyone in this situation to begin with also likely forgot to download separate copies of the NPKs for use by netinstall-cli. Now what are you going to do? Email them over LTE from your phone to your laptop, then use that same phone as a hotspot to retrieve that same email since the laptop no longer has Internet access otherwise?

    The wise path is to have your fallback plan in place before the upgrade.

There is one other possible benefit to using my scripts instead of taking the manual path below: my update script keeps the version of netinstall-cli in lock-step with the version of RouterOS NPKs it downloads. I do not include this in the above list because I do not know how important this practice is. I can envision cases where you would want to use a newer version of netinstall-cli with older RouterOS NPKs, but never the reverse.

Manual Method

Perhaps you dislike my wrapper script, or perhaps you wish to dig deeper.

My prior recommendation was a command like this:

sudo netinstall-cli \
    -i enp0s5 \
    -r -s reset.scr \
    routeros-7.19.4-arm.npk \
    wireless-7.19.4-arm.npk \
    wifi-qcom-7.19.4-arm.npk \
    container-7.19.4-arm.npk

Resetting the configuration (-s) is optional, and you can choose to accept the default config instead of what I’ve done here, but I wanted to show the option. The referenced reset.scr file is given below.

Default Router Configuration Script

My choice above to reset the configuration and apply a fresh configuration lets us do something fun and useful:

/interface bridge add name=bridge
/interface bridge port
add bridge=bridge interface=ether1
add bridge=bridge interface=ether2
add bridge=bridge interface=ether3
add bridge=bridge interface=ether4
/ip dhcp-client add interface=bridge
/user add name="foo" password="bar" group="full"

This is the reset.scr file referenced above, and although it is intended for any of MikroTik’s small WiFi routers, it should serve as a minimalist starting configuration for a wide range of devices.

The bridge setup configures it as a wired-only smart switch. Even if you have a WiFi device and you do want to use it as such, starting your configuration with the radios disabled is good practice. You want to set up the bands, radio power levels, and encryption secrets before exposing a wireless network that radiates outside your building.

The DHCP client lets you do several of these routers and connect them to a setup LAN without creating IP address collisions.

The default user step gets you around MikroTik’s new policy of resetting the admin user’s password to a random value printed in tiny text on a small sticker on the bottom of the router.10

There’s one subtlety to this: netinstall-cli will yell if you name the script other than *.scr. I happen to think it ought to accept the *.rsc extension it uses on /export, but oh, well.

Tips

If you get the “Key was rejected” message, hit Ctrl-C to break out of netinstall-cli, then Up-Arrow and Enter to quickly restart it. I’ve seen this bypass the symptom when using a CentOS 8 Stream VM as the server.

License

This work is © 2023-2025 by Warren Young and is licensed under CC BY-NC-SA 4.0


  1. ^ Always keep telling yourself that Windows is the “easy” OS. You’ll come to believe it, eventually, no matter how much evidence mounts up to the contrary.
  2. ^ This is part of what bridging buys us: the VM doesn’t even know about the host’s alternate interfaces.
  3. ^ Even if your work temporarily precludes access to the DHCP server, the lease you got on booting the VM should last plenty long to regain connectivity.
  4. ^ There merely needs to be an unimpeded L2 path between the two.
  5. ^ That was once required, but netinstall-cli now knows how to discover the local IP scheme and extend it.
  6. ^ Software bridges, tunnels, phony VM NICs, etc.
  7. ^ This is why we cannot use setup-alpine-q. Without this enabled, the "apk add fossil” command fails.
  8. ^ If the product specs merely say “ARM,” it means 32-bit.
  9. ^ There is a non-zero chance that this will fail, and you will need to retry the command. The cause is the same one that results in RouterOS configuration GUIs claiming there are no package updates available even though you know darn well there are.
  10. ^ To be fair, I fully support this policy; in fact, I proposed essentially what we eventually got on the forums long before they implemented it. I’m more annoyed that it took European Union legislation to arm-twist MikroTik into doing this than I am irritated by the fact that it now requires use of either a strong magnifier or a small trainable child before you can learn what that default password actually is on a device like the hAP ax lite, where it’s printed at 37 DPI using a 3pt dot matrix font.🙄 I’m showing you how to get around this password not because I believe in discarding this excellent security measure but to show that you don’t need to know the password to reset it. My recommendation is to treat this as a temporary password only; one of your first steps should be to give it your own long, random password, one not printed on any stickers anywhere.

Attachments: