Appearance
Enrolment
Enrolment is the act of a Brain joining MUXEN's support network for the first time. It happens once in the life of a boat, it takes a few seconds, and after it nothing on board changes: the crew sees no new screen, no new menu and no new alarm. What changed is on the other side — a MUXEN engineer can now reach that boat.
The rest of this chapter is the mechanism, for whoever has to commission or repair it.
What muxen-eagle-init decides, in order
The script is a chain of short-circuits, and the order is the design. Each step exists to avoid doing damage at a later one.
1. Is this a legacy install?
If /var/lib/netbird/default.json exists and its ManagementURL.Host is eagle.muxen.fr:443, the boat was enrolled by an older release of this package, on NetBird's default profile rather than on a profile called eagle. That is a perfectly good enrolment. The script says
Already connected using default profile (legacy install)deletes the key and exits 0. It does not migrate the boat onto the eagle profile — a working remote link is not worth breaking for tidiness.
2. Is NetBird managing the system SSH client config?
NetBird writes /etc/ssh/ssh_config.d/99-netbird.conf unless told not to, and that file changes the behaviour of every outbound ssh on the Brain. The script checks whether the netbird service already carries NB_DISABLE_SSH_CONFIG=true in its environment, and only if it does not:
sh
netbird service reconfigure --service-env NB_DISABLE_SSH_CONFIG=trueThe check exists because reconfigure regenerates the netbird unit and restarts the daemon. Doing that on every run — on a service that retries every five minutes — would be a permanent low-grade disturbance. A netbird package upgrade wipes the setting, which is why the script re-applies it when it is missing rather than assuming it was done once.
3. Is the boat already connected to eagle?
sh
netbird status --jsonIf .management.url is https://eagle.muxen.fr:443 and.management.connected is true, the script says Already connected to eagle, deletes the key and exits 0.
This is the single most important short-circuit, and it comes before anything touches a profile. netbird status --json is stable across NetBird client generations, where the profile commands are not — so on a boat that is already fine, the script never reaches the code that could create a duplicate profile. A restart loop can therefore never pile up damage.
4. Is there a setup key?
Only now is /etc/muxen/eagle.key read, and only to check that it holds at least one non-whitespace character. Everything below this point needs it; nothing above it does. Since the key is deleted on success, its absence is the normal state of a healthy boat, which is exactly why the two checks above come first.
With no usable key, the script distinguishes three cases from the management URL NetBird reports — a value it reports from stored config even while the boat is offline:
| Reported management URL | Interpretation | Message | Exit |
|---|---|---|---|
https://eagle.muxen.fr:443 | enrolled, merely offline | Enrolled with eagle but not connected yet; leaving it to netbird | 0 |
| (empty) | the netbird daemon is not answering yet | netbird daemon not answering yet; will retry | 1 |
| anything else | never enrolled, and no key to enrol with | No setup key at … and not enrolled: cannot register with eagle | 78 |
Exit 78 is EX_CONFIG, and it is the one failure the unit refuses to retry. The other two are retryable by construction: an offline boat needs nothing but time, and a daemon that has not come up yet will.
5. Select the eagle profile.
Two generations of NetBird client have to be supported here, and they disagree about what a profile is:
| Client | Profiles keyed by | Duplicate names | profile list --show-id |
|---|---|---|---|
| older | name — unique | not possible | not supported |
| newer | ID | allowed | supported |
The script probes netbird profile list --show-id to tell them apart.
- Older client. List the profiles, strip the leading marker characters, look for an exact line
eagle;profile add eagleif it is not there;profile select eagle. - Newer client. Collect the ID of every row naming
eagle— the ID column being an 8-or-more hex-character prefix. Add the profile if there are none. Then read/var/lib/netbird/active_profile.jsonand keep theeaglewhose listed ID prefixes the active one, falling back to the first; remove every othereagleduplicate; select the one kept by ID.
Keeping the active duplicate matters: that is the profile carrying the peer registration. Selecting by ID matters because on a newer client profile select eagle fails outright once two profiles share that name — which is precisely the failure that produced the duplicates in the first place. Removals are best-effort: a duplicate that refuses to go does not abort the run.
6. Bring the link up.
sh
netbird up --management-url https://eagle.muxen.fr \
--setup-key-file /etc/muxen/eagle.key \
--allow-server-ssh \
--enable-ssh-local-port-forwarding \
--enable-ssh-remote-port-forwarding \
--enable-ssh-sftpThe four SSH options are what make the link useful for support: an SSH server reachable over the overlay, port forwarding in both directions, and SFTP for pulling logs off the boat and pushing files onto it.
--setup-key-file rather than --setup-key is a security choice, not a style one. A key on the command line is readable by every local user through /proc/<pid>/cmdline for as long as up runs.
7. Delete the key.
set -e is in force, so this line is reached only when up succeeded. From here the netbird daemon holds its own peer credentials and the setup key is dead weight. The script removes it and exits 0.
The retry policy
| Directive | Value | Effect |
|---|---|---|
Restart | on-failure | any non-zero exit is retried |
RestartSec | 300 | five minutes between attempts |
StartLimitIntervalSec | 0 | no rate-limit window |
StartLimitBurst | 0 | no attempt ceiling |
RestartPreventExitStatus | 78 | except this one |
Retries are slowed down, not bounded. A boat with no internet for a week retries every five minutes for a week and enrols the moment it gets a route. This is why the systemd start rate limiter is switched off: with it on, systemd would give up after a handful of attempts and leave the boat permanently unenrolled for want of patience.
The single exception, exit 78, is a configuration error — a package built without a setup key, on a boat that was never enrolled. Retrying cannot fix it, so the unit stops at failed where monitoring can see it.
What makes it run again
After a successful run the unit sits at active (exited). It re-runs when:
- the Brain reboots, with
muxen-deploy.target; muxen.targetis restarted. The unit isPartOf=muxen.target, so a restart of that target stops it, and the deploy target then pulls it back up. Every MUXEN package that activates themuxen-restart-targetdpkg trigger — this one included — causes that restart on upgrade;- you start it by hand, with
systemctl restart muxen-eagle.
Re-running it on an enrolled boat costs one netbird status --json call and stops at step 3. That is the intended steady state.
Idempotence, and its one limit
Every step is written to be safe to repeat. Re-selecting the active profile is a no-op, netbird up on a connected peer is accepted, and the two already-connected checks mean a healthy boat never gets as far as touching a profile at all.
The limit is worth knowing: the script never un-enrols a boat. There is no path in it that leaves the eagle network, removes the eagle profile, or points the Brain at a different management server. A Brain that has to be moved to another network, or taken off the fleet at end of life, is a NetBird operation done by hand and on the management server — not something this package can do.
