Skip to content

service linux

Eric Busboom edited this page Sep 24, 2026 · 1 revision

Service on Linux (systemd)

mbregistry install-service, the unit and udev rule it writes, drop-ins, logs, upgrade and uninstall. Covers Raspberry Pi OS, Debian and Ubuntu.

Service on Linux (systemd)

This page assumes mbtools is installed in /opt/mbtools (see Installing mbtools). The steps are the same on Raspberry Pi OS / Debian (aarch64) and Ubuntu (x86_64).

Install and start

sudo /opt/mbtools/bin/mbregistry install-service
sudo systemctl daemon-reload
sudo systemctl enable --now mbregistry.service
sudo udevadm control --reload-rules
sudo udevadm trigger
sudo usermod -aG plugdev "$USER"        # then open a new login session
mbregistry list                          # as a normal user

install-service writes two files and prints (does not run) the systemctl / udevadm / usermod commands above. It is idempotent: it rewrites identical content and never touches the running service. Without root it fails with could not write ...: Permission denied and exits 1.

Flag Default
--output PATH /etc/systemd/system/mbregistry.service
--udev-output PATH /etc/udev/rules.d/99-mbregistry-cmsis-dap.rules
--user NAME $SUDO_USER, then $USER, then current user. Only affects the printed usermod line

The unit's ExecStart= uses the Python interpreter that ran install-service. Run it from the venv you want the service to use.

The unit it writes

With /opt/mbtools/bin/python3 as that interpreter:

[Unit]
Description=mbregistry -- micro:bit device registry daemon
After=network.target

[Service]
Type=simple
ExecStart=/opt/mbtools/bin/python3 -m mbtools.registry.cli run
Restart=on-failure
RestartSec=2
RuntimeDirectory=mbregistry
StateDirectory=mbregistry

[Install]
WantedBy=multi-user.target

The service runs as root, so it uses the system paths. StateDirectory= and RuntimeDirectory= create them:

Path
Database /var/lib/mbregistry/devices.db
Local API socket /run/mbregistry/api.sock (mode 0666: any local user can use it)

A normal user's mbregistry list, mbdeploy, mbserial and mbrelay try their own per-user socket first and then this one, so they need no flags.

For comparison, mbregistry run as a normal user (foreground, testing) uses $XDG_STATE_HOME/mbregistry/devices.db (default ~/.local/state/mbregistry/devices.db) and $XDG_RUNTIME_DIR/mbregistry/api.sock (or ~/.cache/mbregistry/api.sock without $XDG_RUNTIME_DIR). Don't run both. One daemon per host.

The udev rule it writes

# CDC-ACM tty device node (mbserial, and pyOCD's DAPLink serial transport)
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", GROUP="plugdev", MODE="0660", TAG+="uaccess"

# Raw USB device node (CMSIS-DAP v2 / WinUSB transport, opened directly by pyOCD)
SUBSYSTEM=="usb", ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", GROUP="plugdev", MODE="0660", TAG+="uaccess"

# hidraw device node (CMSIS-DAP v1 / HID transport)
KERNEL=="hidraw*", ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", GROUP="plugdev", MODE="0660", TAG+="uaccess"

(The real file also starts with a comment header.) The rule is for local clients run by a normal user. The root daemon doesn't need it. On an SSH-only host the plugdev group does the work, and a new membership needs a new login session.

Adding flags or environment variables

Don't edit the unit, because install-service overwrites it. Use a drop-in:

sudo systemctl edit mbregistry.service
[Service]
# env-var settings (see Command reference for the full list)
Environment=MBREGISTRY_REMOTE_PORT=7440
# flags with no env var (--peer, --no-relay-pool, --interval) need ExecStart replaced:
ExecStart=
ExecStart=/opt/mbtools/bin/python3 -m mbtools.registry.cli run --no-relay-pool --peer host-a
sudo systemctl restart mbregistry

Set --no-relay-pool on hosts with no relay boards. See Robot-console compatibility.

Everyday operation

systemctl status mbregistry
systemctl is-active mbregistry
sudo systemctl restart mbregistry
journalctl -u mbregistry -f              # follow
journalctl -u mbregistry -b              # since boot

The log is quiet by design. It holds the start-up line plus warnings and errors, with no INFO messages. The start-up line names everything bound:

mbregistry: listening on /run/mbregistry/api.sock (local api), 7440 (remote api), store at /var/lib/mbregistry/devices.db, peering active (pub 7442, snapshot 7443), relay pool on 7444, names API on 7445

Restart=on-failure / RestartSec=2 means a crash (e.g. a port already in use) shows up as a restart loop. journalctl shows the traceback.

Upgrade

sudo /opt/mbtools/bin/pip install --upgrade "git+https://github.com/League-Microbit/mbtools.git"   # or @<tag>
sudo /opt/mbtools/bin/mbregistry install-service
sudo systemctl daemon-reload
sudo systemctl restart mbregistry
mbregistry list

The database is kept and its schema migrates itself on start. If you recreate the venv instead (e.g. uv venv --clear), stop the service first. The root daemon leaves root-owned __pycache__ files behind. Upgrade one host at a time and check mbregistry list on it and on one peer.

Uninstall

sudo systemctl disable --now mbregistry
sudo rm /etc/systemd/system/mbregistry.service /etc/udev/rules.d/99-mbregistry-cmsis-dap.rules
sudo systemctl daemon-reload && sudo udevadm control --reload-rules
sudo rm -rf /opt/mbtools /var/lib/mbregistry      # optional

Migrating a host off the old daemons

A host that ran mbdeploy serve (mbdeploy.service) or the legacy mbrelay.service needs those stopped and disabled before mbregistry starts, because they hold the same USB ports:

sudo systemctl disable --now mbdeploy.service     # if present
sudo systemctl disable --now mbrelay.service      # if present (relay hosts)

Keep their unit files until the new service has proven itself. Rollback is disable --now mbregistry followed by enable --now of the old unit. Which hosts have been migrated is recorded on the internal Robot Garage wiki.

Clone this wiki locally