Skip to content

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. The exit code is machine-readable: 0 all green, 3 when one or more rows is ✗ (a red edge and a broken CLI are different facts — the command itself failing is 1). With --fix it exits 0 unless a repair errored. --no-external skips the through-CDN reachability probes.

CheckHealthy looks likeWhen it fails
identitypresentmissing — run burrowee edge cli bootstrap <blob> <pin>; the machine has never been bootstrapped (or was purged).
fd limitthe installed service unit's LimitNOFILE meets the floorThe unit predates the floor (an old install) — --fix regenerates it.
raw portdisabled when raw_port is unset, else reachable and not fronted by nginxSee Edge-to-edge bridging.
tls listenfrontier :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 internetThree 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 reachableA domain the console pushed is missing from the front (drift), or unreachable. The fault row echoes the real error and distinguishes "config unreadable — needs sudo or an ownership fix" from "signature unverifiable — re-pair", and only points at --fix when --fix can actually repair it. --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 reachablethe console's relay endpointThe 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 listenerA 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 reachableThe LAN snippet is missing or nginx isn't running — --fix installs/starts it.
host cert (frontier edges)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). The check runs against the effective host FQDN even when the host_fqdn config key has drifted, so a drift can no longer skip the cert check exactly where it mattered (the symptom was CDN 5xx errors).
versioninstalled vs running, per componentFlags 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. A stopped edge daemon is itself a remediation --fix offers (it starts the service), it completes a partially-adopted config after a migration, and when the unprivileged account can't read the root-owned config tree it offers to re-read as root rather than misreporting a healthy edge as broken.

sh
burrowee edge doctor --fix --yes

After fixing, it re-probes and prints the settled state.

Legacy per-user units and the linger flap

Since 0.2.0 the edge runs as system-level units (com.burrowee.edge — a LaunchDaemon on macOS, /etc/systemd/system/burrowee-edge.service on Linux), which are immune to this. A pre-0.2.0 install ran as a systemctl --user service instead, and without sudo loginctl enable-linger <user> that user service manager — and the edge with it — was torn down ~12 seconds after the last SSH session closed, then restarted 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. The lasting fix is to move to the system units: update the edge (the migration adopts the install), or run burrowee edge service install. service status still reports any legacy per-user unit it finds.

Status ​

sh
burrowee edge status

status is the read-only alias of doctor: the same report, and always exit 0 — safe for scripts and cron, where doctor's exit 3 on a red row is the point. Nothing is probed destructively and nothing is fixed; when a row is ✗, doctor --fix is the acting form.

Alongside the health rows above, the report carries the operational snapshot of the served configuration. The cached config's signature is verified against the console's key before it is shown — 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
FieldMeaning
owner tenantThe account this edge is bound to.
max gatewaysHow many gateways the manifest allows on this edge.
custom domains / served domainsThe domains attached to and served through this edge.
gateways (fp)How many gateway fingerprints are authorized to use it.
config ageHow 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     # lay down + start the system units (sudo)
burrowee edge service status      # both units' states, legacy per-user ones included
burrowee edge restart             # restart the serve unit (alias of `service restart`)

service install writes system-level units — com.burrowee.edge and com.burrowee.edge.updater as LaunchDaemons on macOS, /etc/systemd/system/burrowee-edge.service (+ the updater's unit) on Linux — and starts the edge. The service runs burrowee-edge run, restarts on failure, and survives reboots (no loginctl enable-linger dance — see the warning box above). The updater's unit is laid down alongside but stays gated: allow_push_update (see Push updates below) controls whether console pushes are allowed, and push allow is what enables + starts the agent. A system unit installed by a different user is never silently replaced — re-running service install --force-service-override is the explicit consent to take it over.

service status reports both units' states, including any legacy per-user unit left from a pre-0.2.0 install. service restart restarts the serve unit through the full legacy→system chain, and offers to elevate when the unit needs root; it 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, the commands say so; run burrowee edge run under your own supervisor instead.

Update ​

sh
burrowee edge update                            # STAGE the current released version (applies on next restart)
burrowee edge updater update --dry              # resolve + print the version gap, install nothing
burrowee edge updater update --auto             # apply and restart immediately
burrowee edge updater update --version <v>      # pin/roll back to an exact version
burrowee edge updater update --force            # full reinstall via the public installer, even when current
burrowee edge updater upgrade                   # update the UPDATER's own binary (update never touches it)
burrowee edge reinstall                         # offline units-only repair: every binary re-laid, config kept

update stages by default: the new binary is placed and takes effect on the next service restart, so an update never interrupts live traffic on its own — --auto is the "apply and restart now" form. Updates are verified end to end and can't silently downgrade — a resolved target older than what's running is refused (an explicit --version rollback is your call). This is the same path a console-initiated push takes, gated by push allow below.

update and upgrade are deliberately two verbs: update moves the edge component, upgrade moves the update agent itself — so a routine component update never restarts the agent performing it. reinstall is neither: an offline repair that re-runs the on-disk install (units and binaries re-laid, no download, config kept).

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 the edge config file, 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 updater is a separate long-running agent (burrowee-edge-updater) with its own health surface, reached through the edge updater passthrough — any command after burrowee edge updater is forwarded to it verbatim:

sh
burrowee edge updater status       # local updater snapshot + a live console-connectivity probe
burrowee edge updater doctor       # the same report; --fix starts the daemon when it is down
burrowee edge updater fingerprint  # print the edge identity fingerprint
burrowee edge updater update       # the component update — see Update above
burrowee edge updater upgrade      # update the agent's own binary
burrowee edge updater reinstall    # offline units-only repair (re-runs the on-disk install, no download)
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 (SIGHUP)
burrowee edge updater version      # the agent's installed and running versions

Every 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, and burrowee edge updater <command> --help reaches the updater's own help pages. Updater health is not part of burrowee edge doctor — that command points you here. The edge version block does include the updater's version alongside the edge's.

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 the config file in the edge config root directly (/usr/local/etc/burrowee/edge/config on a system install — ~/.burrowee/edge/config only on a host with no system install). Most keys have a dedicated command that also writes them (mode → serve_mode, push → allow_push_update, lan-listen → lan_listen, proxy-protocol → proxy_protocol, bridge raw-port → raw_port, cert issue/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 512m

Three 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:

KeyMeaningAccepts
buffer_streamPer-stream receive windowA size with a k/m/g suffix, or a bare byte count
buffer_sessionPer-session receive bucketSame
buffer_frameFrame 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:

  1. persists the new port — a privileged value (like :443) is mapped to the loopback 127.0.0.1:9443 first, since the unprivileged daemon can't bind it directly,
  2. reconciles the nginx front to the new port by shelling out to nginx reconcile --mode <mode> (see nginx front),
  3. 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 restarting

The 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 `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 system unit, so:

    sh
    journalctl -u burrowee-edge.service -f

    (A legacy pre-0.2.0 per-user install logs under journalctl --user -u burrowee-edge.service instead.)

  • macOS: the LaunchDaemon doesn't write a log file. For live logs, stop the service and run in the foreground:

    sh
    burrowee 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. Every stderr line from all three edge binaries is timestamped, so logs from different components line up.

Uninstall ​

sh
burrowee edge uninstall            # remove the service, BACK UP config + state
burrowee edge uninstall --purge    # remove the service, DELETE everything

The default is non-destructive: it stops and removes the service units, then moves the nginx stream snippet and the edge's config and data trees 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 config   → /usr/local/etc/burrowee/edge.bak.20260612-101500
  edge state    → /usr/local/var/burrowee/edge.bak.20260612-101500
restore:   mv <backup> back to its original path
reinstall: burrowee edge service install && burrowee edge nginx install

Restoring really is just the mv — the identity, console config, and certificates all live in the backed-up directories.

--purge deletes instead: the snippet, the edge's config and data trees, 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).