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:

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. --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 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).
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.

sh
burrowee edge doctor --fix --yes

After 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 status

Three possible shapes, depending on how far setup has gone:

  • not enrolled — run burrowee edge cli bootstrap <blob> <pin>; no identity on this machine.
  • enrolled; no config received yet (run burrowee-edge run while approved + connected, then re-check) — bootstrapped, but the signed manifest hasn't arrived over the carrier.
  • The full readout. Before printing it, status verifies 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
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     # install + start the managed service
burrowee edge service status      # is it loaded/active?
burrowee edge restart             # restart it

service 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 binary

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. 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 (modeserve_mode, pushallow_push_update, bridge raw-portraw_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 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 `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:

    sh
    journalctl --user -u burrowee-edge.service -f
  • macOS: the launchd agent 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.

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 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 install

Restoring 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).