Sunday, 30 March 2025
Upgrading to the Mikrotik RouterBoard RB2011, Part 2 - DHCP
This is Part 2 of my RB2011 series - [here's Part 1](https://blog.themillhousegroup.com/2025/01/upgrading-to-mikrotik-routerboard.html). You can find the [whole series here](https://blog.themillhousegroup.com/search/label/routerboard).
## DNSMasq Replacement
First, let's replace the `dnsmasq` instance on the Raspberry Pi (which does DHCP, DNS and ad-blocking via Pi-Hole-style `0.0.0.0` resolution). As mentioned before, this will free up the Pi to just be a server again, rather than a critical bit of network infrastructure, but also:
- allow the DHCP pool to be modified from a web UI (easier if using a phone in a pinch)
- make the current DHCP client list visible in a browser
- allow DHCP modifications without having to restart DNSmasq
### DHCP on RouterOS v7
Some other nice properties of the [Mikrotik DHCP server](https://help.mikrotik.com/docs/spaces/ROS/pages/24805500/DHCP#DHCP-DHCPServer) include:
#### Multiple pools with different behaviour
- I like the idea of having "trusted" devices (with a known MAC and fixed IP address) getting better bandwidth, and this is entirely possible with the `rate-limit` property of (leases](https://help.mikrotik.com/docs/spaces/ROS/pages/24805500/DHCP#DHCP-Leases)
- It would be nice to also represent this status with some bit-flagging in the IP address itself, as per my [cunning scheme](https://blog.themillhousegroup.com/2011/04/ultimate-ubuntu-build-server-guide-part_25.html)
#### Event scripting
- you can run a [script upon lease assignment or de-assignment](https://help.mikrotik.com/docs/spaces/ROS/pages/24805500/DHCP#DHCP-DHCPServerProperties)
- could be handy to trigger presence-like automated behaviour
To minimise interruption to network users, we'll do this in a staged manner, gradually moving services over to the RB2011.
### Move to a static IP for the RouterBoard
This is critically important, and if you don't do it right, you're highly-likely to end up with the dreaded unreachable router. Ask me how I know...
To do this in one fell swoop, switch to the Quick Set tab in the top of the web interface. Make the configuration mode __Router__ but leave the Address Acquisition settings alone - we're not going to be using `ETH1`, for our intents and purposes, it's cursed. Then just fill out the Local Network IP settings you'd like the RB2011 to have, but turn off DHCP Server at this stage (we're not ready for that yet) and NAT - our existing gateway device does NAT for us.
Hit *Apply Configuration*, say a small prayer to `${DEITY}` and reload the page (at the new IP address if you changed it). Give it a minute or two before you punt it across the room...
### DHCP Server with single address pool
Next up, we'll set up a DHCP server to do that aspect of what we're currently doing with DNSMasq - a single address pool for unspecified random (a.k.a "guest") devices for which we don't have a mapping, plus a bunch of fixed IPs for known devices. For a smooth switchover, first we'll bring the lease times of everyone getting leases from the Pi *down* to a short interval, to get them roughly "in sync".
Backup the old `dnsmasq.conf` on the Pi:
```
% cd /etc
% sudo cp dnsmasq.conf dnsmasq.conf.pre-rb2011
```
Bring the lease time DOWN for everyone, by going into `dnsmasq.conf` and changing the `dhcp-range` (for random/guest devices) and each `dhcp-host` entry (for known devices) like this:
```
dhcp-range=10.240.0.64,10.240.0.96,1h
...
dhcp-host=00:11:22:33:86:7e,somebox,10.240.0.100,2h
```
to
```
dhcp-range=10.240.0.64,10.240.0.96,5m
...
dhcp-host=00:11:22:33:86:7e,somebox,10.240.0.100,5m
```
Restart dnsmasq for the changes to take effect:
```
pi % sudo service dnsmasq restart
```
Now over on the RB2011, we can run the built-in DHCP Server "wizard" from the SSH prompt:
```
[admin@MikroTik] > /ip/dhcp-server/setup
Select interface to run DHCP server on
dhcp server interface: bridge
Select network for DHCP addresses
dhcp address space: 10.0.0.0/8
Select gateway for given network
gateway for dhcp network: 10.240.0.1
Select pool of ip addresses given out by DHCP server
addresses to give out: 10.240.0.32-10.240.0.63
Select DNS servers
dns servers: 10.240.0.200
Select lease time
lease time: 1800
[admin@MikroTik] >
```
But then immediately disable it:
```
[admin@MikroTik] > /ip/dhcp-server/print
Columns: NAME, INTERFACE, ADDRESS-POOL, LEASE-TIME
# NAME INTERFACE ADDRESS-POOL LEASE-TIME
0 dhcp1 bridge dhcp_pool1 30m
[admin@MikroTik] > /ip/dhcp-server/disable numbers: 0
```
We can now fine-tune the config at our leisure, and enable it once we're entirely ready.
__Set the `domain` so clients have a FQDN:__
```
[admin@MikroTik] > /ip/dhcp-server/network/set numbers=0 domain=home.themillhousegroup.com
```
__Ensure each client gets an ARP table entry:__
```
[admin@MikroTik] > /ip/dhcp-server/set numbers=0 add-arp=yes
```
### Known MAC addresses
I have a reasonably-long list of device MAC addresses (about 30) that I want to have "stable" IP addresses; this is a "static lease" in Mikrotik-speak.
A typical dnsmasq host line looks like:
```
dhcp-host=00:11:22:33:86:7e,somebox,10.240.0.100,15m
```
Each line becomes (for example):
```
[admin@MikroTik] > /ip/dhcp-server/lease/add mac-address=00:11:22:33:86:7e comment=somebox address=10.240.0.100 lease-time=900
```
But note the `hostname` from DNSMasq has just become a comment. To get the nice behaviour that DNSMasq gives us where a DNS entry is created, we need to also add a DNS entry:
```
[admin@MikroTik] > /ip/dns/static/add name=somebox address=10.240.0.100 ttl=900
```
30 entries was too much like manual labour for me, so here's a [little shell script in a Gist](https://gist.github.com/themillhousegroup/41fba50b448ba8f10166decbe2fcc890). Feed it your `dnsmasq.conf` and it'll spit out all the configuration lines you'll need to make your Mikrotik work like DNSMasq did; i.e. a static DHCP server lease and a static DNS entry. Paste the output into your RouterOS SSH session, and confirm that you've got a nice list in the UI at _IP_ -> _DNS_ -> _Static_.
Once you're all set, we're going to take down dnsmasq's DHCP and bring up the RouterOS service as close-together as possible. To do this, first you'll need to tell dnsmasq to NOT listen on the usual interface. On my Pi running Raspbian Buster, this is unfortunately not something predictable like `eth1`, but rather something you'll need to copy-paste from the output of `ifconfig`; e.g.:
```
pi $ ifconfig
enxb827ebfdad60: flags=4163 mtu 1500
inet 10.240.0.200 netmask 255.255.255.0 broadcast 10.240.0.255
```
Edit `/etc/dnsmasq.conf`, adding that ethernet identifier to the `no-dhcp-interface` line (if there is one)
```
# If you want dnsmasq to provide only DNS service on an interface,
# configure it as shown above, and then use the following line to
# disable DHCP and TFTP on it.
no-dhcp-interface=lo,enxb827ebfdad60
```
And now it's swap-over time:
```
pi % sudo service dnsmasq restart
```
```
[admin@MikroTik] > /ip/dhcp-server/enable numbers: 0
```
Then watch the Pi's `/var/lib/misc/dnsmasq.leases` get shorter and the Mikrotik's _IP_ -> _DHCP Server_ -> _Leases_ start to fill up!
Don't forget to backup your settings!
The new DHCP responses still point to the Pi for DNS resolution; we'll configure that next time...
Labels:
dhcp,
dnsmasq,
gist,
github,
homeautomation,
markdown-enabled,
mikrotik,
routerboard
Saturday, 22 February 2025
Introducing ... Blitzcore!
My family has become quite addicted to an excellent little card game called [Dutch Blitz](https://en.wikipedia.org/wiki/Dutch_Blitz). It's easy to learn, compact, reasonably quick to play (although the exact length of an entire game can vary *wildly*...) and it's lots of fun.
The only downside is the scoring system, which involves pen-and-paper and certain amount of maths, making the scorekeeper role unappealing to younger players.
To this end, I'm pleased to release [Blitzcore](https://blitzcore.themillhousegroup.com) ("Blitz-Score") to the world, allowing your phone to do the maths for you and present a clear picture of the score [1](#foot-1).
Paintakingly designed to fit onto exactly one phone-sized browser page like [all good mobile-first webapps](https://blog.themillhousegroup.com/2023/08/searching-for-next-spa.html), it uses bright colours that match the game, big easy-to-hit buttons, and just-in-time calculation to ensure the score is always accurate, no matter what you just edited.
Your player name and colour preferences are stored in LocalStorage to make it even quicker to get going next time.
This is my first "big" (not really) webapp in [Svelte 5](https://svelte.dev/) and [SvelteKit](https://svelte.dev/docs/kit/introduction) and it's been a pretty delightful experience. I `push` to my Github private repo and Netlify (free tier) picks it up and publishes to the world in about 45 seconds. The page load time is absolutely stupendous - Svelte/SvelteKit/Vite is absolutely killing it here.
The only trouble I've ever had has been occasionally Svelte *not* reacting to a change when expected, which so-far has been 100% due to my failure to wrap derived values in [the `$derived()` rune](https://svelte.dev/docs/svelte/$derived). It can be quite a pain to track down these things, which seemed to mostly be around manipulating array entries (using `slice` and friends), but I got there in the end. Enjoy!
---
1 To be clear, this is not a version of the game itself - the creators have actually [attempted to do this for mobile devices](https://dutchblitz.com/), which I have never tried ... [⤴︎](#foot-1-src)
Labels:
dev,
dutch-blitz,
markdown-enabled,
netlify,
node.js,
svelte,
typescript
Wednesday, 22 January 2025
Upgrading to the Mikrotik RouterBoard RB2011, Part 1
For my home network, I needed a firewall that offers an API that I can call from elsewhere (on the trusted side of the network). Think "default block ALL", then an API call comes in to temporarily open one port to one IP address for an hour, before reverting back to "block all".
There are precious few network devices that actually offer this capability; at first this seemed surprising but then I guess there's less overlap between _"I configure secure small networks"_ and _"I write backend code"_ than I thought.
Fortunately, Mikrotik's [RB2011UiAS-RM](https://mikrotik.com/product/RB2011UiAS-RM) (RB2011 for short) is an absolute network Swiss Army Knife, capable of a heap of stuff that I've had a long-suffering Raspberry Pi 3B doing - things like DNSMasq (and domain blocking à la Pi-Hole) and WireGuard VPN termination. I'd like to take those tasks off the trusty Pi, leaving it to be a true application server rather than a bit of network infrastructure. Of course there are many devices that can perform these tasks, but the Mikrotik stands above the rest with its [control-plane API](https://help.mikrotik.com/docs/spaces/ROS/pages/47579162/REST+API), which lets me do the dynamic-firewall thing I need, rackmountability (I 3d-printed the ears) and the fact that it is **fanless** and thus completely silent in operation.
_**Aside**: Here's a little tip if you find something a bit niche, but a bit overpriced, on eBay. **Stick a watch on it**. Eventually, the seller will get notified by eBay and prompted to offer *you*, the watcher, a 10% discount. This has been my strategy for low-urgency nerd items for a while and it works a treat._
Here's how I've got it going.
# Finding it
Firstly (and this may just be some leftover configuration on my secondhand device that a factory reset didn't clear out for some reason), I couldn't get the device to respond in *any* way over the network until the following conditions were *all* true:
- Port `ETH1` plugged in to my existing network
- IP address allocated to `ETH1` via DHCP
- Port `ETH2` plugged into my laptop (Wifi OFF)
- IP address allocated to laptop via DHCP over that link
This is counter to every bit of documentation (Mikrotik-official or otherwise) I've found online that says the router will factory-reset to `192.168.88.1` and will run a DHCP server to hand out `192.168.88.0/24` IPs to connected clients.
Once I'd discovered (via looking at DNSMasq logs on the Pi) that the router was coming online in this way, it was actually a pleasure to use, as it's always annoying having to flip back-and-forth between multiple networks while setting these things up. Effectively the router's web UI is accessible at whatever IP you want to give its `ETH1` MAC via DHCP, and the rest of the `ETH` ports just come up as a "bridge", making the device feel like a simple 10/100/1000 switch, that happens to have a nice UI.
On the subject of UI, Mikrotik does offer a native control application [(WinBox)](https://mikrotik.com/download) but it's not really needed unless you're having major issues finding your device on the network (but see above for some hints!) as it can do some "neighbour discovery" stuff. For me, my 2012 MacBook Pro is running too ancient a MacOS to even consider it. The Web UI ("`webfig`") plus SSH are easily enough for me. After decades of absolutely awful consumer-grade router web UIs, `webfig` is snappy, modern enough, well-considered and bug-free.
# Upgrade to v7 and Initial setup
The RB2011 has 128Mb of RAM, allowing it to be [upgraded to Version 7 of RouterOS](https://help.mikrotik.com/docs/spaces/ROS/pages/115736772/Upgrading+to+v7) (important, because that's the version in which the REST API becomes available). Going from v6.49.17 to v7 is as easy as going to _System -> Packages -> Check for Updates_ and switching the _Channel_ to `upgrade`. `v7.12.1` shows up (in January 2025 at least) and is just a _Download and Install_ away. From there, we're on the v7 train and can go as bleeding-edge as desired. For me the `stable` channel seemed like a safe bet, so I further updated to `7.17` (January 2025).
### Backup
Once we've done that, we should also start [backing up](https://help.mikrotik.com/docs/spaces/ROS/pages/40992852/Backup) the router config after every successful stage of setup. Log in as `admin` via SSH and just do `[admin@MikroTik] > /system/backup/save`. You can see the file from the *Files* top-level menu in the UI or in the console with `/file print`:
```
[admin@MikroTik] /file> print
# NAME TYPE SIZE LAST-MODIFIED
0 skins directory 1970-01-01 11:00:05
1 pub directory 2019-10-23 12:13:14
2 auto-before-reset.backup backup 44.1KiB 1970-01-01 11:00:06
3 MikroTik-20250122-2026.backup backup 28.2KiB 2025-01-22 20:26:13
[admin@MikroTik] /file>
```
### Turn off unwanted services
RouterOS runs a [number of IP services](https://help.mikrotik.com/docs/spaces/ROS/pages/328229/IP+Services) that we neither want nor need; turning them off can only be of benefit; `telnet` and `ftp` are ancient and insecure; we've already established that `winbox` is surplus to requirements. Eventually, it would be good to only allow the `-ssl` versions of the `www` and `api` services, but we'll leave them for now. `ssh` is always wanted.
So to begin, let's see what we have:
`/ip/service/print`:
```
Flags: X - DISABLED, I - INVALID
Columns: NAME, PORT, CERTIFICATE, VRF, MAX-SESSIONS
# NAME PORT CERTIFICATE VRF MAX-SESSIONS
0 telnet 23 main 20
1 ftp 21 main 20
2 www 80 main 20
3 ssh 22 main 20
4 X www-ssl 443 none main 20
5 api 8728 main 20
6 winbox 8291 main 20
7 api-ssl 8729 none main 20
```
Now we can turn them off:
`/ip/service/disable telnet`
`/ip/service/disable ftp`
`/ip/service/disable winbox`
We can also reduce the maximum number of concurrent sessions to something more realistic. It's probably unimportant, but it shows off a cool feature of the command-line:
```
/ip/service/set max-sessions=3
numbers: 2,3,4,5,7
```
...we can apply the same setting change to all the different services in one go. That's really cool. Here's what we have now:
```
Flags: X - DISABLED, I - INVALID
Columns: NAME, PORT, CERTIFICATE, VRF, MAX-SESSIONS
# NAME PORT CERTIFICATE VRF MAX-SESSIONS
0 X telnet 23 main 20
1 X ftp 21 main 20
2 www 80 main 3
3 ssh 22 main 3
4 X www-ssl 443 none main 3
5 api 8728 main 3
6 X winbox 8291 main 20
7 api-ssl 8729 none main 3
```
**Reminder**: Time to backup again!
Subscribe to:
Posts (Atom)