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
netinstall
likely 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.npk
extra-package has been installed and other RouterOS specifics, and/system/device-mode
has 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/veth
interface/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
netinstall
use 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=ether5
or, if the physical port is already in a bridge port, reassign it instead:
/interface bridge port [find interface=ether5] bridge=bridge-netinstall
NOTE
Replace
ether5
with 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-netinstall
TIP
Alternatively, you can /ip/firewall/filter or NAT rules on the containers subnet, to specifically allow VETH access to the internet. Traffic between
netinstall
is forwarded, not routed, so only needed for outbound access from the container's IP. How? - depends... -
Create some environment variables to control
netinstall
operation – 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-url
is used to fetch "pull" images. Either DockerHub or GitHub Container Registry are supported. Use/container/config/print
to view theregistry-url
andtmpdir
in use on RouterOS (if any).For DockerHub, the
registry-url
setting should behttps://registry-1.docker.io
, if not set use:/container config set registry-url=https://registry-1.docker.io tmpdir=disk1/pulls
NOTE
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-netinstall
NOTE
Or, to use GHCR (ghcr.io), instead of DockerHub, the above would use
remote-image=ghcr.io/tikoci/netinstall
instead.Or, if you built your own
.tar
file usingdocker buildx
, do not useat all. Instead, useremote-image=
file=
that contains the path of the.tar
image uploaded to the router.The rest of the attributes to
/container add
are 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/print
to 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
VER
when 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
Dockerfile
to build yourtar
image.
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/env
and documented here.
For Linux useexport VER_NETINSTALL=7.14.2
in a.profile
or 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 theMakefile
directly. -
Provided via
make
at CLI, in same directory as Makefile. For example, to start netinstall for mipsbe using theVER
number directly, with some extra packages and-a 192.168.88.7
option, and specific versionnetinstall
to 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.15rc3
which results in the following
netinstall
command 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.npk
TIP
Any
make
at CLI, can be used as the/container cmd=
as an alternive to environment variables. -
Editing the
Makefile
All 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 updatedMakefile
harder.TIP
In the
Makefile
take careful note to use tab indentations –make
will 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/mount
can used, and the "container-relative" full path referenced in sameOPTS
after 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
, andunzip
installed 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
make
from 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
sudo
must be used on most desktop Linux distros for any operation that starts runningnetinstall
, since privileged ports are used. But just downloading files, should not requireroot
orsudo
– but runningnetinstall
might 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
netinstall
options can be also provided using theVAR=VAL
scheme 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"
OPTS
is 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.PKGS
is only for extra-packages – the baserouteros*.npk
is always included (based onARCH
andVER
).
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, thenmake
can 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 theCHANNEL
to usemake <arm|arm64|mipsbe|mmips|smips|ppc|tile>
- specify theARCH
to 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
make
variables 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/shell
without 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:
make
is very good at maintaining a directory with all the needed files, so it downloads only when needed efficiently.- By using
.PHONY
targets, and non-traditional target names,make
this approach act more "script-like" than a C/C++ build tool. make
natively supports taking variables from either viamake
arguments 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/