Appearance
Operations
The day-2 surface: checking health, reading state, managing the service, and removing an edge cleanly.
Doctor
sh
burrowee edge doctor [--fix] [--yes] [--no-external]Runs the health checks, one line each, in order:
| Check | Healthy looks like | When it fails |
|---|---|---|
| identity | present | missing — run burrowee edge cli bootstrap <blob> <pin>; the machine has never been bootstrapped (or was purged). |
| fd limit | the installed service unit's LimitNOFILE meets the floor | The unit predates the floor (an old install) — --fix regenerates it. |
| raw port | disabled when raw_port is unset, else reachable and not fronted by nginx | See Edge-to-edge bridging. |
| tls listen | frontier :443 (unprivileged bind) or off (LAN-only edge) | A privileged tls_listen (the default :443) on an unprivileged service crash-loops — --fix rebinds it to a loopback port and fronts that with nginx. |
host front config / local / external (frontier edges with host_fqdn set only) | config applied, :443 reachable locally, and reachable through the public internet | Three separate rows so a failure is attributed to the right layer: a red external row with a healthy local row means the problem is upstream (Cloudflare, DNS, your firewall) — --fix cannot repair that layer, only report it. --no-external skips the internet probe. |
| custom domain routing (frontier edges only) | every console-attached custom domain is present in the installed SNI front and reachable | A domain the console pushed is missing from the front (drift), or unreachable. --fix reconciles the front — it re-pushes the SNI map so the console's domain set and the installed front agree. --no-external skips the per-domain reachability probe. |
| console reachable | the console's relay endpoint | The edge can't reach the console over WebSocket. An auth-level rejection still counts as reachable — only a transport failure (DNS, firewall, outbound blocked) fails this line. |
| lan front (frontier mode) | not in LAN mode — informational; a frontier edge has no LAN listener | A leftover LAN front from a previous LAN-mode run is still on disk — --fix removes it. |
| LAN front (LAN mode — expands to nginx installed/running + config + reachability rows) | nginx installed + running, config applied, :8448 → 127.0.0.1:9448 reachable | The LAN snippet is missing or nginx isn't running — --fix installs/starts it. |
host cert (frontier edges with host_fqdn set only) | valid until <date> | Missing, or expiring within 30 days — --fix issues/renews it via Cloudflare DNS-01 (prompting for a token if none is stored). |
| version | installed vs running, per component | Flags drift after a binary swap that hasn't restarted yet. |
--fix remediates in dependency order, each step best-effort and consent-gated (skip prompts with --yes): refresh the service unit → rebind a privileged tls_listen → fix the public host front → fix the LAN front → remove any stale leftover front from a prior mode → issue/renew the host cert → restart the service so everything takes effect.
sh
burrowee edge doctor --fix --yesAfter fixing, it re-probes and prints the settled state.
systemd --user needs linger
burrowee-edge installs as a systemctl --user service. Without sudo loginctl enable-linger <user> on the host, the user service manager — and the edge with it — is torn down about 12 seconds after the last SSH session to that user closes, then restarts on the next login. The signature is a clean stop/start (not a crash) whose timestamps line up with SSH logins, plus flapping symptoms downstream: a Cloudflare 525 on a CF-proxied edge, "connection reset by peer" for direct clients, or repeating bridge link down spam on a bridged edge. Fix once per host: sudo loginctl enable-linger <user>, then confirm systemctl --user show burrowee-edge -p ActiveEnterTimestamp stays identical across two separate logins. A root/system install (curl … | sudo sh) is unaffected — it runs a system unit, not a user one.
Status
sh
burrowee edge statusThree possible shapes, depending on how far setup has gone:
not enrolled— runburrowee edge cli bootstrap <blob> <pin>; no identity on this machine.enrolled; no config received yet (runburrowee-edge runwhile approved + connected, then re-check)— bootstrapped, but the signed manifest hasn't arrived over the carrier.- The full readout. Before printing it,
statusverifies the cached config's signature against the console's key — a stale or tampered file is an error, never silently served:
owner tenant: 42
max gateways: 10
custom domains: [app.example.com]
served domains: [app.example.com]
gateways (fp): 3 authorized
config age: 2m10s| Field | Meaning |
|---|---|
owner tenant | The account this edge is bound to. |
max gateways | How many gateways the manifest allows on this edge. |
custom domains / served domains | The domains attached to and served through this edge. |
gateways (fp) | How many gateway fingerprints are authorized to use it. |
config age | How long ago the console issued the current manifest. A fresh sync resets it — an ever-growing age suggests the carrier is down. |
Service
sh
burrowee edge service install # install + start the managed service
burrowee edge service status # is it loaded/active?
burrowee edge restart # restart itservice install writes a launchd agent on macOS (~/Library/LaunchAgents/org.burrowee.edge.plist) or a systemd user unit on Linux (~/.config/systemd/user/burrowee-edge.service), and starts it. The service runs burrowee-edge run, restarts on failure, and survives reboots. It also installs and starts the updater agent (burrowee-edge-updater) alongside it — the updater running is harmless on its own, since allow_push_update (see Push updates below) still gates whether it's actually allowed to apply anything. The one exception is a root/system install on Linux (curl … | sudo sh): its systemd unit for the updater is written but left disabled, so a system install starts opted-out until you systemctl enable --now burrowee-edge-updater yourself.
restart kicks the service (launchctl kickstart -k / systemctl --user restart) and then prints the nginx-front status lines, read-only — it never touches nginx itself. If the front is down it points you at doctor --fix.
On a platform without launchd or systemd, both commands say so; run burrowee edge run under your own supervisor instead.
Update
sh
burrowee edge update # install the latest release, then restart the service
burrowee edge update --dry # report the version gap + changelog only
burrowee edge update --force # re-install even when already current
burrowee edge update --auto # skip the confirmation prompt
burrowee edge update --no-restart # install but don't restart the service
burrowee edge update --version <stamp> # pin/roll back to a specific console-catalog release
burrowee edge update --console <url> # override the console base URL (default https://console.burrowee.com)update always prints the version gap and changelog first, then restarts the service only when the binary or unit actually changed (skipped when already current unless --force); a restart failure is non-fatal since the new binary is already in place. This is the same command an owner runs by hand as it is the one the updater agent runs on a console-initiated push — see below.
Push updates
sh
burrowee edge push allow # opt in — the console may push an update to this edge
burrowee edge push stop # opt out — takes effect immediately, no restart needed
burrowee edge push status # cloud push-updates: STOPPED (allow_push_update=false)push flips allow_push_update in ~/.burrowee/edge/config, which the standalone burrowee-edge-updater agent (installed alongside the service, above) reads on every console-initiated update request. Default: stopped. This gate only covers console-initiated pushes — running burrowee edge update yourself is always available regardless of the flag, since it's a local action you triggered. push allow also installs+starts the updater agent's own service unit and push stop disables+stops it, so the opt-in takes effect immediately.
The updater agent
The cloud-push updater is a separate long-running agent (burrowee-edge-updater) with its own health surface, reached through the edge updater passthrough:
sh
burrowee edge updater status # local updater state + a live console probe
burrowee edge updater doctor # updater health rows; --fix starts the daemon
burrowee edge updater fingerprint # print the edge identity fingerprint
burrowee edge updater apply [--version <stamp>] # install a specific edge version locally
burrowee edge updater reinstall # re-run the install flow for the current version
burrowee edge updater enable # opt in (== push allow): set allow_push_update + start the agent
burrowee edge updater disable # opt out (== push stop): unset it + stop the agent
burrowee edge updater restart # signal the running agent to restart onto a fresh binaryEvery verb forwards to the standalone burrowee-edge-updater binary, so the output is identical whether you go through burrowee edge updater … or run it directly. Cloud-push updater health is not part of burrowee edge doctor — that command points you here (run \burrowee edge updater doctor` for cloud-push updater health`).
Config
sh
burrowee edge config get [key] # print one key, or every key sorted, if omitted
burrowee edge config set <key> <value>Reads and writes ~/.burrowee/edge/config directly. Most keys have a dedicated command that also writes them (mode → serve_mode, push → allow_push_update, bridge raw-port → raw_port, cert/bootstrap → host_fqdn) — reach for config for everything else, like the buffer profile knobs or rebinding a listener when a default port clashes with something already on the machine.
Buffer profile
sh
burrowee edge config get buffer_stream
burrowee edge config set buffer_session 512mThree optional keys tune the receive-window buffers the edge advertises to every peer that dials it (cli, gateway, and any bridged edge) — useful on a high bandwidth-delay-product path, where the small library defaults cap raw-forward throughput:
| Key | Meaning | Accepts |
|---|---|---|
buffer_stream | Per-stream receive window | A size with a k/m/g suffix, or a bare byte count |
buffer_session | Per-session receive bucket | Same |
buffer_frame | Frame size (rarely changed) | Same |
The installer seeds buffer_stream=32m / buffer_session=256m on a fresh install and rolls the same defaults onto an existing edge the first time it updates across the release that introduced them — always seed-if-absent, so a value you've set yourself is never overwritten. Peers adopt whatever the edge advertises on their next (re)connect; nothing to configure on the cli or gateway side. Larger windows are a memory cap, not a reservation — an idle carrier holds nothing near it.
Keeping the front in sync
The console can push a new tls_listen port to a frontier edge (from the Edge relays page). When that happens the edge, over its live carrier:
- persists the new port — a privileged value (like
:443) is mapped to the loopback127.0.0.1:9443first, since the unprivileged daemon can't bind it directly, - reconciles the nginx front to the new port by shelling out to
nginx reconcile --mode <mode>(see nginx front), - restarts itself to rebind, but only if the effective port actually changed.
edge: console pushed tls_listen=:443 (effective 127.0.0.1:9443) — reconciling front then restartingThe reconcile step needs to write /etc/nginx, which the unprivileged daemon can't do directly on Linux. When the front was first installed under root (sudo burrowee edge nginx install), that step left behind a narrow passwordless-sudo rule scoped to exactly the service user and the reconcile command — so the daemon can now reconcile nginx on every console-pushed change without a manual doctor --fix. If that rule isn't in place (an edge whose front predates it, or one never installed under root), the daemon logs a hint instead of blocking:
edge: nginx front reconcile: <error> — run `sudo burrowee edge doctor --fix`doctor --fix is the reliable backstop for that case; running it after any console-pushed port or mode change is always safe (idempotent) even when nothing was actually stuck. To install (or refresh) the passwordless reconcile rule, re-run sudo burrowee edge nginx install once.
Logs
Linux: the service is a systemd user unit, so:
shjournalctl --user -u burrowee-edge.service -fmacOS: the launchd agent doesn't write a log file. For live logs, stop the service and run in the foreground:
shburrowee edge run
The foreground run logs the carrier connection, the serving mode decision, and every listener — it is the primary debugging surface on any platform.
Uninstall
sh
burrowee edge uninstall # remove the service, BACK UP config + state
burrowee edge uninstall --purge # remove the service, DELETE everythingThe default is non-destructive: it stops and removes the launchd/systemd service, then moves the nginx stream snippet and the whole ~/.burrowee/edge/ directory aside with a timestamped .bak.<timestamp> suffix, and reloads nginx so it stops serving the front. Nothing is lost:
uninstalled burrowee-edge (config + state backed up, not deleted):
nginx snippet → /etc/nginx/servers-stream/burrowee-edge-stream.conf.bak.20260612-101500
edge state → /home/user/.burrowee/edge.bak.20260612-101500
restore: mv <backup> back to its original path
reinstall: burrowee edge cli service install && sudo burrowee edge cli nginx installRestoring really is just the mv — the identity, console config, and certificates all live in the backed-up directory.
--purge deletes instead: the snippet, the edge home, and any .bak.* backups from earlier uninstalls. Use it when decommissioning a machine for good. The identity is unrecoverable afterwards — re-enrolling means minting a fresh blob in the console.
Both forms accept --home and --conf-dir if the edge lives in non-default locations. The nginx reload is best-effort (it may need sudo); a failure prints the manual sudo nginx -s reload and never blocks the removal. Removing the relay from your account is a separate, console-side act: Edge relays → [≡] menu → Deactivate (then Delete to drop the row entirely).