Replacing an Omada ER7206 with a MikroTik RB5009: our migration script
How we moved a home network from a controller-managed TP-Link ER7206 to a MikroTik RB5009 on RouterOS 7, including the import script and what went wrong.
- An RB5009 cannot be adopted by an Omada controller, so every setting has to be carried over by hand. We dumped the old site config to JSON first and wrote one RouterOS script from it.
- The inventory came down to: one LAN subnet that had to stay the same, 12 DHCP reservations, a 1-day lease, DNS, and two port forwards. We dropped the forwards entirely.
- The LAN address change goes on the last line of the script. The first version had it near the top, and that ordering only works if nothing else depends on your session.
- Management services are restricted to the LAN, unused services are disabled, and an SSH key is added for scripted administration. The key line in our script did not take effect, and we added the key afterwards.
We replaced a TP-Link ER7206, which was managed by an Omada software controller, with a MikroTik RB5009 running RouterOS 7. This post covers what we inventoried, the script we imported, the ordering mistake we fixed partway through, and the cleanup items still open. All addresses below are examples. We use 10.0.0.0/24 for our LAN, and 192.168.88.0/24 appears only as the RouterOS factory default.
Inventory first: dump the old controller to a file
Omada stores the router’s real configuration in the controller, not on the router. The configuration backups we had from a few weeks earlier were already missing later changes, so we pulled a fresh snapshot through the controller’s Open API. We saved devices, WAN status, LAN networks, DHCP reservations, port forwards, attack-defense settings, UPnP, SNMP, the client list, and device-access settings into one JSON file, and treated that file as the source of truth. We had also kept a hand-written network diagram, and it turned out to be wrong in three places: it listed forwards and a DNS server that no longer existed, and it was missing the tunnel. Check the live config. Don’t trust your own notes.
What the snapshot said needed to move:
| Item | On the ER7206 | On the RB5009 |
|---|---|---|
| WAN | DHCP from the ISP, no double NAT, IPv6 off | ether1, DHCP client (defconf), IPv6 disabled |
| LAN | one /24, router on .1 |
same subnet, so the RouterOS default 192.168.88.0/24 has to change |
| DHCP pool | .100–.199, 24-hour lease, DNS = router + 1.1.1.1 |
same, lease-time=1d |
| Reservations | 11, plus one we added (12 total) | static leases in the script |
| Port forwards | 2: an FTP control port and a passive range, both to the NAS | none |
| UPnP / DMZ | off / none | UPnP off, no DMZ host |
Keeping the same subnet was not optional. One always-on machine had a static address and gateway configured by hand. The printer was added on other computers by IP rather than by name. The NAS firewall allowed management only from that /24. Changing the subnet would have meant touching every one of those.
Two decisions came out of the inventory. First, nobody used FTP from outside anymore, so we dropped both forwards. The router now has zero inbound forwards. Our web services leave the house through an outbound Cloudflare Tunnel, so they did not depend on any forward. Second, the inventory showed that one machine’s primary DNS server was the NAS’s address, where an ad-blocking DNS container had just been removed. Lookups were only succeeding because the client fell back to its second server. We changed it to the router plus 1.1.1.1 before the swap so that problem would not get blamed on the new router.
The script, sanitized
This is the second version of the script we imported, with our addresses, MACs, device names and key removed. It assumes a factory RouterOS 7 default configuration (defconf): a bridge called bridge, ether1 as WAN, a DHCP server called defconf, and the default firewall.
# RB5009 initial config v2 — values carried over from the old controller.
# The LAN address change is LAST, so a dropped WebFig session can't cut the script short.
# Apply: WebFig (http://192.168.88.1) -> Files -> upload -> Terminal: /import rb5009-initial.rsc
# -- basics --
/system identity set name=RB5009
/system clock set time-zone-name=<your/Timezone>
/system ntp client set enabled=yes
:do { /system ntp client servers add address=time.cloudflare.com } on-error={}
:do { /system ntp client servers add address=time.google.com } on-error={}
/ip dns set servers=1.1.1.1,<secondary-resolver> allow-remote-requests=yes
# -- admin SSH key (did NOT take effect for us, see below) --
:do { /user ssh-keys add user=admin key="<your-ssh-public-key>" } on-error={ :put "ssh-key add failed" }
# -- management plane: LAN only; old default subnet allowed during the move --
/ip service set [find name=telnet] disabled=yes
/ip service set [find name=ftp] disabled=yes
/ip service set [find name=api] disabled=yes
/ip service set [find name=api-ssl] disabled=yes
/ip service set [find name=www] address=10.0.0.0/24,192.168.88.0/24
/ip service set [find name=ssh] address=10.0.0.0/24,192.168.88.0/24
/ip service set [find name=winbox] address=10.0.0.0/24,192.168.88.0/24
/tool mac-server set allowed-interface-list=LAN
/tool mac-server mac-winbox set allowed-interface-list=LAN
/ip neighbor discovery-settings set discover-interface-list=LAN
/tool bandwidth-server set enabled=no
/ip upnp set enabled=no
/ip proxy set enabled=no
/ip socks set enabled=no
/ipv6 settings set disable-ipv6=yes
# -- DHCP reservations (12 in ours; three shown) --
/ip dhcp-server lease
:do { add server=defconf address=10.0.0.117 mac-address=<nas-mac> comment=nas } on-error={}
:do { add server=defconf address=10.0.0.137 mac-address=<server-mac> comment=always-on-mini } on-error={}
:do { add server=defconf address=10.0.0.146 mac-address=<printer-mac> comment=printer } on-error={}
/ip dhcp-server set [find name=defconf] lease-time=1d
# -- optional: clone the old router's WAN MAC if the ISP binds to it --
# /interface ethernet set [find default-name=ether1] mac-address=<old-wan-mac>
# -- LAST: 192.168.88.0/24 -> 10.0.0.0/24 (your session drops here) --
/ip pool set [find name=default-dhcp] ranges=10.0.0.100-10.0.0.199
/ip dhcp-server network set [find] address=10.0.0.0/24 gateway=10.0.0.1 dns-server=10.0.0.1,1.1.1.1
:do { /ip dns static set [find name=router.lan] address=10.0.0.1 } on-error={}
/ip address set [find interface=bridge] address=10.0.0.1/24 network=10.0.0.0
A few notes on the choices:
:do { … } on-error={}wraps lines that can fail harmlessly on a second run, such as an NTP server or a lease that already exists. An unhandled error can stop the import partway through, and anything after it, including the LAN change, would not run.- Reservations reference
server=defconf, the DHCP server the default configuration creates. If you have rebuilt the router from a blank config, change the name. lease-time=1dmatches the old router’s 24 hours. Most clients on a home LAN are reserved anyway. A day-long lease keeps renewal traffic low, and an address freed by a departed guest still comes back the next day.- The WAN MAC clone is commented out. Some ISPs authenticate the first MAC they see. Ours didn’t, and the connection came up without it.
Why the LAN change has to be the last line
Version 1 of the script set the new bridge address on line 16, directly after the basics. The plan was to apply it from a laptop on ether2 with the WAN unplugged, connected through WinBox by MAC address, which survives an IP change.
That isn’t what happened. The new router was cabled in before the script ran, so it booted on its factory 192.168.88.0/24. Clients that use DHCP moved to the factory subnet and still had internet. The NAS and the always-on machine kept their old 10.0.0.x addresses and became unreachable from everything else. Scheduled jobs on that machine would have failed overnight.
At that point the only easy way in was WebFig over IP from a machine on the factory subnet. When a script changes the bridge address, the HTTP session it is running from dies. Any line after that point depends on how the import behaves once its controlling session is gone, and we didn’t want to bet the reservations on that. So version 2 puts everything that doesn’t affect reachability first and the four lines that move the LAN at the very end. If the session drops on the final line, the work is already done.
We applied it by uploading the .rsc in WebFig’s Files menu and running /import rb5009-initial.rsc in WebFig’s Terminal. The browser stopped responding, as expected. Once we reconnected, the router answered on 10.0.0.1. The NAS and the always-on machine were reachable, the router resolved DNS, and an external check of a tunnelled web service returned HTTP 200. We checked the reservations through the ARP table. Nine of the twelve reserved devices had their expected addresses. The other three (a printer, a laptop and a games console) were powered off, so they still need checking.
SSH key admin and the service lockdown
The management block does three things:
- Turns off what we don’t use. Telnet, FTP, the API and API-SSL are disabled outright, along with the bandwidth-test server, UPnP, the web proxy and SOCKS.
- Restricts what’s left to the LAN. WebFig (
www), SSH and WinBox only accept connections from listed prefixes. MikroTik’s Services documentation says the service still sees packets from other sources but refuses access to them. The old default subnet stays on the list until the move is finished. MAC-WinBox, MAC-Telnet and neighbor discovery are limited to theLANinterface list. - Adds an SSH key so scripted administration doesn’t need a password.
Step 3 failed silently for us. After the import, key login was refused (Permission denied (publickey,password)), and we never found the reason. Our script line included a trailing comment after the base64 key. We fixed it afterwards with one password SSH session that ran /user ssh-keys add user=admin key="ssh-ed25519 <base64>", using only the key type and the key body, with no comment. The fingerprint appeared in /user ssh-keys print and key login worked from then on. MikroTik’s SSH documentation describes /user ssh-keys import public-key-file=… user=admin after uploading the .pub file, which is the documented route if the inline form gives you trouble.
That page also says password-authentication defaults to yes-if-no-key, which means password login over SSH is only allowed for users with no key. We haven’t verified how our router ended up, so run /ip ssh print on yours rather than assuming. WebFig and WinBox still take the password, so keep it in a password manager.
Things we found after the swap
- Two addresses on the bridge. When we inspected the router over SSH later, the bridge carried both the factory
192.168.88.1/24(commentdefconf) and the new LAN address (commentLAN). The script usesseton the existing address, so we expected one. We haven’t traced why there were two. Removing the factory address is on the cleanup list. Leave it in place until no client still holds a192.168.88.xlease. - Spanning tree versus the mesh Wi-Fi. According to our notes, with RSTP on the bridge, BPDUs travelling through the mesh access points put two wired ports into blocking states and wired throughput dropped to about 300 Mbps. We set
/interface bridge set bridge protocol-mode=none. This is a trade-off: with STP off, nothing protects against a loop if someone patches two LAN ports together, so think about your own topology before copying it. The RouterOS STP documentation explains the port roles involved. - A port that linked at 100 Mbps. One run to a mesh node negotiated only 100 Mbps. We suspect the cable or the wall jack, and we disabled that port until it is replaced rather than leave a slow link in the mesh.
- Device mode. Our RB5009 runs in
device-mode=home. Our notes record that some features, including the scheduler and RouterBOARD settings, are restricted in that mode. That affects automation plans, because you can’t rely on on-router scheduled scripts, so check/system/device-mode/printbefore designing around them.
What we’d do differently
- Order every migration script by blast radius: harmless settings first, access restrictions next, and the change that cuts your own session last.
- Wrap anything idempotent in
on-error={}so the script can be re-run safely after a partial apply. - Verify the SSH key by logging in with it before you rely on it. A single
ssh -o BatchMode=yes [email protected] /system identity printright after import would have caught our failed key line immediately. - Keep the old router untouched. We left the ER7206 unchanged, with its config still in the controller, so rolling back means moving one cable. We plan to remove the controller only after the new router has been stable for a while.
- Cut over between scheduled jobs, not across them. We checked the cron tables on the always-on machine first and picked a window with nothing due.
Next, we used this router to put a backup server on its own subnet that can reach only the NAS. That setup is in isolating a server in a RouterOS DMZ with one exception. The server itself was built with an unattended Debian 13 install ISO.