netinstall allows the "flashing" of Mikrotik devices, using a list of packages and various options. While Mikrotik provides a Linux version of netinstall, running it involves many steps. One of which is the downloading packages, for the right CPU, possibility some "extra-packages" too.
Mikrotik has a good overview of netinstall and the overall process: https://help.mikrotik.com/docs/display/ROS/Netinstall#Netinstall-InstructionsforLinux
The source code and CI image building are stored in a public GitHub repo, and an OCI is also pushed to DockerHub by GitHub's Actions. Comments, complaints, and bugs are all welcome via GitHub Issues in the tikoci/netinstall repo.
The "script" is invoked by just calling make from the same directory, and by default that will start a netinstall using ARM packages, from "stable" channel, on an interface named "eth0". This is often not the case, so variables on the network interface/IP will likely need to be changed from defaults.
There is an associated Dockerfile to enable containerization, including using QEMU to run Mikrotik's X86 netinstall binary on other platforms, specifically ARM and ARM64/aarch (see forked code). By default, this container runs as a "service", so after one netinstall completes, it goes on to waiting for the next.
/container running netinstall is handy to enable reset/recovery of a connected RouterOS device without needing a PC. The basic approach is a container's VETH is bridged to a physical ethernet interface, using a new /interface/bridge for "netinstall". Then the container runs the Linux netinstall using emulation (on arm/arm64). The trick here is no /container/mounts are needed – install packages are downloaded automatically based on the environment variables provided to the image.
Using "vlan-filtering=yes" bridge should work if VETH and target physical port have some vlan-id=. But for
netinstalllikely best if just separate, since VLANs add another level of complexity here. Possible, just untested and undocumented here.
- RouterOS device that supports containers, generally ARM, ARM64, or X86 devices
- Some non-flash storage (internal drives, ramdisk, NFS/SMB client via ROS, USB, etc.)
container.npkextra-package has been installed and other RouterOS specifics, and/system/device-modehas been used to enable container support as well.
See Mikrotik's docs on /container for more details and background, including how to install the prerequisites:
https://help.mikrotik.com/docs/display/ROS/Container
Instructions below assume a non-flash disk is at disk1/ and ether5 is where the device to be "netinstall'ed" is connected. Adjust examples needed.
-
Create
/interface/vethinterface/IP:/interface veth add address=172.17.9.200/24 gateway=172.17.9.1 name=veth-netinstall /ip address add address=172.17.9.1/24 interface=veth-netinstall -
Create a separate bridge for
netinstalluse and add VETH to it:/interface bridge add name=bridge-netinstall /interface bridge port add bridge=bridge-netinstall interface=veth-netinstall -
Add veth and physical port, e.g. "ether5", to the newly created bridge:
/interface bridge port add bridge=bridge-netinstall interface=ether5or, if the physical port is already in a bridge port, reassign it instead:
/interface bridge port [find interface=ether5] bridge=bridge-netinstallNOTE
Replace
ether5with the ethernet interface to device needingnetinstall. -
Adjust the firewall so the container can download packages/netinstall binary from Mikrotik. The exact changes needed can be specific. But if using the default firewall, the easiest may be:
/interface/list/member add list=LAN interface=bridge-netinstallTIP
Alternatively, you can /ip/firewall/filter or NAT rules on the containers subnet, to specifically allow VETH access to the internet. Traffic between
netinstallis forwarded, not routed, so only needed for outbound access from the container's IP. How? - depends... -
Create some environment variables to control
netinstalloperation – adjusting allvalue=as needed:/container envs add key=ARCH name=NETINSTALL value=arm64 /container envs add key=CHANNEL name=NETINSTALL value="testing" /container envs add key=PKGS name=NETINSTALL value="container zerotier wifi-qcom iot gps" /container envs add key=OPTS name=NETINSTALL value="-b -r" comment=" use EITHER -r to reset to defaults or -e for an empty config; use -b to remove any branding" -
The
registry-urlis used to fetch "pull" images. Either DockerHub or GitHub Container Registry are supported. Use/container/config/printto view theregistry-urlandtmpdirin use on RouterOS (if any).For DockerHub, the
registry-urlsetting should behttps://registry-1.docker.io, if not set use:/container config set registry-url=https://registry-1.docker.io tmpdir=disk1/pullsNOTE
Ensure
disk1/is a valid disk and has at least ~150MB available. Some routers may need the formusb1-part1/or similar. The disk path can be a cheap USB stick to run the container even – just not a router's boot flash. Non-specific errors may result if an invalid path is used. -
Create the container. This assumes DockerHub is used:
/container add remote-image=ammo74/netinstall:latest envlist=NETINSTALL interface=veth-netinstall logging=yes workdir=/app root-dir=disk1/root-netinstallNOTE
Or, to use GHCR (ghcr.io), instead of DockerHub, the above would use
remote-image=ghcr.io/tikoci/netinstallinstead.Or, if you built your own
.tarfile usingdocker buildx, do not useat all. Instead, useremote-image=file=that contains the path of the.tarimage uploaded to the router.The rest of the attributes to
/container addare the same as example.It will take about a minute to download and process the image file. After the new container is expanded, it is indicated as a "stopped" status (instead of "expanding" or "error"). Status can be shown by using
/container/print.If you see "error" status means something failed, likely disk or firewall issues. Worth it to check the
/logs/printto where the process has failed. -
Now start container! Use:
/container/start [find tag~"netinstall"]TIP
If you have any issues, first check the logs:
/log print proplist=time,message where topics~"container"
All options are described in greater detail later. But CHANNEL, ARCH, PKG, and OPTS are the typical ones. But some additional /container/env include:
Instead of using CHANNEL like "stable", to select the version use:
/container envs add key=VER name=NETINSTALL value=7.12.1
If both CHANNEL and VER are used, VER wins.
TIP
It recommend you only set
VERwhen needed, since it overrides what is set inCHANNEL. This may be what you want – just as a default "stable" makes more sense.
To set the version of netinstall use:
/container envs add key=VER_NETINSTALL name=NETINSTALL value=7.15rc3
Left unset, the version of netinstall itself will follow what is set in CHANNEL, which defaults to "stable".
While these variables control networking, they shuld not be needed with /container as it should be automatic via -i eth0. If not, file a bug.
The container can be built locally into the .tar file needed by RouterOS as an alternative to "pull". The specific steps depending on your environment. Generally, adapt the steps here with Mikrotik's example Docker build steps for Pi-Hole.
To begin, use git clone https://github.com/tikoci/netinstall.git to download needed Dockerfile and Makefile (that contains the netinstall logic) to your PC & use these with docker buildx as described in Mikrotik's doc. With a few more steps you get a .tar for use on RouterOS – without using DockerHub or GHCR.
TIP
See example/builder/README.md for a sample
Dockerfileto build yourtarimage.
Let's start with some commons ones, directly from the Makefile script — these are the defaults if left any unset elsewhere:
ARCH ?= arm
PKGS ?= wifi-qcom-ac
CHANNEL ?= stable
OPTS ?= -b -r
# ...
These can used in three ways:
-
Using environment variables This is generally most useful with containers since environment variables are the typical configuration method.
For Mikrotik RouterOS these are stored in/container/envand documented here.
For Linux useexport VER_NETINSTALL=7.14.2in a.profileor similar. This allows environment variables to persist on a Linux shell, similar to a container. i.e. to avoid always having to provide them every time without having to edit theMakefiledirectly. -
Provided via
makeat CLI, in same directory as Makefile. For example, to start netinstall for mipsbe using theVERnumber directly, with some extra packages and-a 192.168.88.7option, and specific versionnetinstallto be used of 7.15rc3:cd ~/netinstall sudo make -d ARCH=mipsbe VER=7.14.3 PKGS="iot gps ups" CLIENTIP=192.168.88.7 VER_NETINSTALL=7.15rc3which results in the following
netinstallcommand line being used:./netinstall-cli-7.15rc3 -b -r -a 192.168.88.7 routeros-7.14.3-mipsbe.npk iot-7.14.3-mipsbe.npk gps-7.14.3-mipsbe.npk ups-7.14.3-mipsbe.npkTIP
Any
makeat CLI, can be used as the/container cmd=as an alternive to environment variables. -
Editing the
MakefileAll of the variables are at the top of the file. The ones with?=are used only if the same variable was not already provided via CLI or env. In general, the only benefit of this method is proximity. The method is not recommended - it makes using some future updatedMakefileharder.TIP
In the
Makefiletake careful note to use tab indentations –makewill fail if space indentations are used.Also, be careful not to change or override computed variables, i.e. variables that use
=or:=assignment. The?=mean default if not provided, so those are the one designed to be "overriden".
The specific file names needed for netinstall are generated automatically based on the ARCH, CHANNEL, and PKGS variables to make things easier to configure. The routeros*.npk does NOT need to be included in PKGS - it is always added based on ARCH. Only items "extra-packages" that needed to be installed are added to PKGS.
| option | default | |
|---|---|---|
| ARCH | arm |
architecture name must match /system/resource |
| PKGS | wifi-qcom-ac |
additional package name(s), without version/CPU, separated by spaces, invalid/missing packages are skipped |
| CHANNEL | stable |
same choices as /system/package/update i.e. testing, long-term |
Each time make is run, the CHANNEL's current version is checked via the web and sets VER automatically.
By design, CHANNEL should be used to control the version used.
If VER (RouterOS) and/or VER_NETINSTALL (executable) are provided, the string must be in the same form as published, like 7.15rc2 or 7.12.1. It cannot be a channel name like "stable". But these variables can be any valid version, including older ones no longer on a channel.
VER_NETINSTALL is useful since sometimes netinstall has bugs or gains new features. Generally, a newer netinstall can, and often should, be used to install older versions i.e. some potential OPTS has changed over time... By default, only CHANNEL controls what version of netinstall will be used. Meaning, even if VER is lower/older than VER_NETINSTALL, the latest "stable" netinstall for Linux will be used by default. That is unless VER_NETINSTALL is specified explicitly
| option | default | |
|---|---|---|
| VER | calculated from CHANNEL |
specific version to install on a device, in x.y.z form |
| VER_NETINSTALL | calculated from CHANNEL |
version of netinstall to use, can be different than VER |
In the variable OPTS, the string is provided directly to netinstall unparsed. So any valid netinstall command line options can be provided – they just get inserted with run.
To get an empty config, change -r in the OPTS variable to a -e (both -r and -e are NOT allowed at some time).
The real netinstall also supports additional options, like replacing the default configuration via an option -s <defconf_file>, among others. These too can be provided in OPTS - along with existing options.
TIP
If netinstall option needs a file,
/container/mountcan used, and the "container-relative" full path referenced in sameOPTSafter flag. For example,-r -s /data/mydefconf.rsc.
| option | default | |
|---|---|---|
| OPTS | -b -r |
default is to "remove any branding" -b and "reset to default" -r, see netinstall docs |
Critical to netinstall working to flash a device is the networking is configured. This is the trickiest part. The -i or -a options must align with everything else, which corresponds to the IFACE OR CLIENTIP.
Mikrotik has a YouTube video that explains a bit about these interface vs IP options: Latest netinstall-cli changes. These are more applicable if you're using Makefile standalone on a Linux machine - if running in a /container, the network default here should work.
In either case, the router and machine (or container's VETH) should be directly connected or on a bridge without ANY other traffic. An IP address should be installed on the system running make. You may need internet or Wi-Fi initially to download the packages (make download).
If used within a Mikrotik /container via the Dockerfile/registry, the defaults should work: -i eth0 ... since the container only has one VETH and the IP config has to work to get to this point.
| option | default | |
|---|---|---|
| IFACE | eth0 |
physical interface name connected to the device to netinstall, i.e. the link name in ip addr |
| CLIENTIP | not set | by default -i <iface> is used, if CLIENTIP then -a <clientip> is used |
| NET_OPTS | calculated | raw netinstall network options, like "-i en4" – IFACE and CLIENTIP are ignored if NET_OPTS is set, only needed if -i <iface> or -a <clientip> do not work (or change) |
To use a branding package, PKGS_CUSTOM variable can be used with /container/mount. The full container-relative path need to be used. The value of PKGS_CUSTOM is simply appended to the end of the netinstall command, so any package with a valid full path can used.
| option | default | |
|---|---|---|
| PKGS_CUSTOM | empty | full path within container to addtional packages, space seperated; any paths must match /container/mount |
This should not be changed, documented here for consistency.
| option | default | |
|---|---|---|
| QEMU | ./i386 |
qemu-user-static is needed to run netinstall on non-Intel platforms (QEMU is NOT used if X86). See Dockerfile, but Alpine Linux does not have a pre-built package, so it's borrowed from a Debian build for use on Alpine. |
| URLVER | https://upgrade.mikrotik.com/routeros/NEWESTa7 | URL used to determine what version is "stable"/etc |
| PKGS_FILES | computed | read-only, in logs shows the resolved "extra-package" to be installed |
- Linux device (or virtual machine) with ethernet
- Some familiarity with the UNIX shell and commands
make,wget, andunzipinstalled on your system.
NOTE
Each distro is different. Only limited testing was done on Linux, specifically virtualized Ubuntu. While very generic POSIX commands/tools are used, still possible to get errors that stop
makefrom running. Please report any issues found, including errors.
You can download the Makefile itself to a new directory, But it may be easier to just use git, to make any future updates easier:
```
cd ~
git clone https://github.com/tikoci/netinstall.git
cd netinstall
```
To test it, just run make download to which will download ARM packages, not NOT run netinstall.
The begin, make needs to be run from the same directory as the Makefile. To use examples, the current directory in shell must be contain the Makefile.
INFO
sudomust be used on most desktop Linux distros for any operation that starts runningnetinstall, since privileged ports are used. But just downloading files, should not requirerootorsudo– but runningnetinstallmight on most Linux distros since it listens on a privileged port (69/udp).
- Download files for "stable" on the "tile" CPU - but NOT run netinstall:
make stable tile download
- The runs netinstall using "testing" (
CHANNEL) build with "mipsbe" (ARCH):sudo make testing mipsbe
- To remove all cached downloaded files:
make clean
- This command will continuously run the netinstall process in a loop.
sudo make service
- All of
netinstalloptions can be also provided using theVAR=VALscheme after themake:make run ARCH=mipsbe VER=7.14.3 VER_NETINSTALL=7.15rc3 PKGS="wifi-qcom container zerotier" CLIENTIP=192.168.88.7 OPTS="-e"
OPTSis ace-in-the-hole since the value it just appended tonetinstall, this can be used to control important stuff like-e(empty config after netinstall) vs-r(reset to defaults) options, or any valid option to netinstall.PKGSis only for extra-packages – the baserouteros*.npkis always included (based onARCHandVER).
The script is based on a Makefile and the make command in Linux. One important detail is that make looks for the Makefile within the current working directory.
make- same asmake run, see belowmake run- CLI default is run netinstall unit found and finished, then stop the containermake service- Dockerfile default runs netinstall as a service until stopped manuallymake download- used on desktop to download packages before potentially disconnecting the network, thenmakecan be used without internet access
Any targets provided via arguments to make will OVERRIDE any environment variable with the same name. i.e. CLI arguments win
make <stable|testing|long-term>- specify theCHANNELto usemake <arm|arm64|mipsbe|mmips|smips|ppc|tile>- specify theARCHto use
For example make testing tile which will start netinstall using the current "testing" channel version, for the "tile" architecture.
For offline use, while only one channel and one architecture can be used at a time...Downloaded files are cached until deleted manually or make clean. So to download without running, add a download to the end of make stable mipsbe download, and repeat for any versions you want to "cache".
TIP
The "shortcut" with
makevariables provided likemake download VER=7.12 ARCH=mmips CLIENTIP=192.168.88.4 VER_NETINSTALL=7.15rc3. Just don't mix TOO many, but output (or logs) should indicate the potential problem
make clean- remove all stored packages and netinstall; will be re-created at startup againmake nothing- does nothing, except keep running; used to access/container/shellwithout starting anythingmake dump- for internal debugging use, not much data
The aim here is to simplify the process of automatically downloading all the various packages and netinstall tool itself. But also an experiment in approaches too. Essentially the "code" is just an old-school UNIX Makefile, but beyond its history, it has some modern advantages:
makeis very good at maintaining a directory with all the needed files, so it downloads only when needed efficiently.- By using
.PHONYtargets, and non-traditional target names,makethis approach act more "script-like" than a C/C++ build tool. makenatively supports taking variables from either viamakearguments or environment variables. This is pretty handy to allow some code to support containerization and plain CLI usage- As a "script interpreter",
make(plus busybox tools) is significantly smaller "runtime" than Python/Node/etc. Before loading the packages, the container image is 6MB.
The disadvantage is that is complex to understand unless one is already familiar with Makefile. It's a dense ~200-page manual (see "GNU make manual" in HTML or PDF).
But since make deals well with state and files, it saves a lot of if [ -f routeros* ] ... fi stuff it takes to do the same as here in bash...
After trying this, it does seem like a nifty trick in the bag to get a little more organization out of what is mainly some busybox and /bin/sh commands. In particular, how it deals with variables from EITHER env or program args. Anyway, worked well enough for me to write it up and share – both the tool and approach.
This work is marked with CC0 1.0. To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/