Appearance
Config homes & files
Each component keeps its state under fixed directories. The CLI stays per-user at ~/.burrowee/cli/. The gateway and edge are system services since 0.2.0, and since 0.3 everything machine-owned sits in one root-owned tree, /usr/local/burrowee/: a config root under /usr/local/burrowee/etc/, a data root under /usr/local/burrowee/var/, and the binaries in the exec root /usr/local/burrowee/bin — which is not on PATH; see Put the exec root on PATH. Nothing is placed in /usr/local/bin. A pre-0.2.0 per-user tree (~/.burrowee/gateway, ~/.burrowee/edge) is a migration source only — the installer's migration ladder adopts it into the system roots (or run migrate --from <dir> yourself).
No runtime component reads BURROWEE_* environment variables (the installers do read a few, like BURROWEE_SKIP_PREFLIGHT — see Install); relocation is by flag only — the CLI's --home (and --config, whose parent directory becomes the home), the gateway's --config-dir/--data-dir (--home is a deprecated alias), and the edge's --home, which names the config root (the data root is always derived from it). Key material is written 0600 inside 0700 directories.
uninstall (without --purge) moves the home aside to a timestamped backup, <home>.bak.<timestamp>, instead of deleting it.
CLI — ~/.burrowee/cli/
Written by burrowee bootstrap <blob> <pin>.
| File | What it holds |
|---|---|
config.json | The relay matrix, schema v4: gateways — each one carrying its own membership as relays: {system, edges, default} (full relay ids) — a shared relays catalog keyed by relay id (kind system|edge, origin, LAN addresses, pinned LAN-cert fingerprint), bridges, defaults (the global default gateway only), and an optional pinned transport mode. One client can be paired with several gateways, each reachable over several relays — see Relays |
config.json.v3.bak | Written once, by the v3 → v4 migration: the exact pre-migration config.json bytes, mode 0600. A secret — it inlines the same service PSK. Restoring it over config.json is the only way back to a pre-v4 CLI (see below) |
ssh_config | OpenSSH-format host aliases read by burrowee ssh, with #@gateway / #@service / #@relay directives |
<svc>_config | The same alias format, generalized per service: burrowee open --svc <svc> <host> resolves <host> from <svc>_config (e.g. vnc_config) |
fingerprints.json | The opt-in browser TLS/HTTP disguise config (burrowee fingerprint path prints this path; disabled by default — stock TLS) |
logs/ | Managed-daemon logs; every stderr line is timestamped, so logs/daemon.err.log is diagnosable after the fact |
identity/client.key | The client's own identity key (0600) — generated on first use, shared across every gateway you pair with |
identity/device.key | The device's identity key — generated on first burrowee login, used to authorize the device with the console for gated downloads |
Both identity keys live under identity/; an older install that kept them flat in the home root is migrated into identity/ automatically on next use. Everything else a pairing needs lives inline in config.json — there are no sidecar files on a fresh pairing. connect / ssh / daemon default their flags from this config. relays pair, relays use, gateways use, and gateways resync edit config.json in place.
How config.json reaches v4 — and the way back
A config.json at v1, v2 or v3 is migrated in place the first time a v4 build loads it, one version at a time, transparently on the next connect, ssh, relays list, etc. Two things about that step are worth knowing before you take it:
The v3 → v4 step writes a backup, and it is the only way back
Before migrating, the CLI writes the exact pre-migration bytes to config.json.v3.bak beside the config (config.beta.json.v3.bak on a beta build), at mode 0600. Treat that file as a secret — it inlines the same service PSK the config does.
An older CLI cannot read a v4 file at all. It decodes strictly, so the per-gateway relays object is an unknown field and every command fails at startup, not just the relay ones. To go back, restore config.json.v3.bak over config.json.
What the v3 → v4 step changes: each gateway's relays split into its system path and its edges, by kind; the old per-gateway default relay becomes relays.default when it was an edge, and the gateway's system path when it was the system relay; the flat edges[] table, the matrix-root defaults.relay, and every stored via are dropped. Bridges, the pinned transport, each relay's default_gateway, and relays keyed by their origin (from a gateway that predates relay ids) all survive it. One thing does not: a relay that has a domain and that you had pinned to LAN by hand loses that pin, and is dialled over its domain from then on — see No stored dial face.
Daemon socket
| Path | Purpose |
|---|---|
~/.burrowee/cli/sockets/transport.sock | The transport daemon's IPC socket — stream consumers receive per-service-sealed streams over it, and every relays/gateways subcommand that mutates state or needs a live answer (use, rm, pair, resync, probe, …) pokes it after editing config.json (the list forms and relays ping read config.json directly and need no daemon — ping dials the relay itself). On a pathologically long home path it overflows to $XDG_RUNTIME_DIR/burrowee/transport.sock (OS temp dir when XDG_RUNTIME_DIR is unset). Override with --socket on daemon/relays/gateways. |
Service unit
Installed by burrowee service install — a system-level unit (written via sudo, run as the installing user), so the daemon starts at boot with no GUI login. One system slot per machine; --force-service-override consents to taking over a unit another user installed.
| Platform | Unit | Path |
|---|---|---|
| macOS (launchd daemon) | com.burrowee.cli | /Library/LaunchDaemons/com.burrowee.cli.plist |
| Linux (systemd system unit) | burrowee-cli.service | /etc/systemd/system/burrowee-cli.service |
Legacy per-user units (org.burrowee.cli gui agent / systemd --user) are migrated away on install but still probed by service status.
Gateway — /usr/local/burrowee/{etc,var}/gateway
The gateway is a system service running as root; its state is split across a config root and a data root (flags --config-dir / --data-dir; the old single --home is a deprecated alias). Created on first serve / bootstrap. The gateway's identity is self-generated — the private keys never leave the config root. Since the microkernel split, the roots are shared by three binaries: burrowee-gateway (the daemon), burrowee-gateway-console (the local console, supervised as the daemon's child), and burrowee-gateway-updater (the push-update agent).
Config root — /usr/local/burrowee/etc/gateway/
| File / dir | What it holds |
|---|---|
identity/relay_ed.key | The gateway's identity key toward relays (its fingerprint is the gateway's id everywhere) |
identity/cli_ed.key | The gateway's identity key toward paired clients |
identity/session.key | Key material for session tokens (generated on first serve) |
config | Optional KEY=VALUE overrides for the few operator-tunable defaults: console_port=<n> (the loopback console port, default 16518) and allow_push_update=false (opt out of console-driven remote push-updates; default true — see push allow|stop|status) |
fingerprints.json | The opt-in browser TLS/HTTP disguise config (burrowee gateway fingerprint path); disabled by default |
console.token | The local console's bearer token, owned root:<admin-group> mode 0640 — reading the signed-in URL (console-url) needs admin-group membership; rotating it (console-rotate-token) needs root |
Data root — /usr/local/burrowee/var/gateway/
| File / dir | What it holds |
|---|---|
gateway.db | The gateway store: persisted relays, targets, sessions, pairings — everything the local console shows |
sockets/ | Runtime unix sockets (see below) |
logs/ | stdout/stderr of the managed service on macOS (every stderr line timestamped); on Linux, logs go to the journal — journalctl -u burrowee-gateway.service |
Upgrading from a pre-0.2.0 install
A legacy per-user ~/.burrowee/gateway tree is adopted one-way into the roots above by the migration ladder that runs on install/update, or explicitly with burrowee gateway migrate --from <dir> (adoption sources only the running user's home). A verified migration retires the tree it adopted from. Until an unmigrated legacy tree is dealt with, bootstrap/run refuse to silently mint a fresh identity — pass --migrate-from <dir> to adopt it or --accept-new-identity to deliberately start over.
Sockets
| Path | Purpose |
|---|---|
~/.burrowee/gateway/sockets/register.sock | Where burrowee-register registers a local TCP service with the running gateway (the default --sock path; burrowee gateway register info prints the resolved path and whether it dials). On an over-long home path, --sock becomes required. |
<data-root>/sockets/console.sock | Where the separate burrowee-gateway-console process talks to the daemon for operations that need it live. |
Service unit
Installed by burrowee gateway service install (and automatically by bootstrap) — system-level units that name --config-dir/--data-dir explicitly and serve the daemon with --no-open. burrowee-gateway-updater gets its own unit installed alongside; there is no separate unit for the console, which runs as a supervised child of the daemon. --force-service-override consents to replacing a unit installed by a different user.
| Platform | Unit | Path |
|---|---|---|
| macOS (launchd daemons) | com.burrowee.gateway, com.burrowee.gateway.updater | /Library/LaunchDaemons/ |
| Linux (systemd system units) | burrowee-gateway.service, burrowee-gateway-updater.service | /etc/systemd/system/ |
Upgrading from an old install
Earlier builds used per-user agents (org.burrowee.gateway, then a per-user com.burrowee.gateway). service install migrates automatically — it boots out and removes the stale unit before installing the current system-level one.
Edge — /usr/local/burrowee/{etc,var}/edge
Written by burrowee edge bootstrap <blob> <pin> and by the running relay. Same split as the gateway: a config root at /usr/local/burrowee/etc/edge and a data root at /usr/local/burrowee/var/edge (root-owned 0700). The edge's --home flag names the config root only — the data root is always derived from it. A host with no system install keeps ~/.burrowee/edge; a pre-0.2.0 per-user tree is adopted with burrowee edge migrate --from <dir> (copies, never moves; a verified adoption renames the source to <tree>.bak.<timestamp> with a printed one-mv recovery) — normally run for you by the shipped migration ladder.
Config root — /usr/local/burrowee/etc/edge/
| File / dir | What it holds |
|---|---|
identity/relay_ed.key | The edge's identity key; its fingerprint is what you approve in the cloud console |
console.json | The enrolled console URL + public key (console_url, console_pub_hex), persisted by bootstrap; the compiled-in console identity is the fallback when absent |
config | Serve settings as KEY=VALUE lines: tls_listen (default :443, off = LAN-only), quic_addr (unset = off), lan_listen (default 127.0.0.1:9448, off), lan_advertise_port, lan_cert, lan_allow_ips, serve_mode (frontier|lan, written by edge mode), raw_port / raw_port_listen (the nginx-bypass isolated listener, unset = off — see Ports), proxy_protocol (default derived: on when tls_listen is loopback/nginx-fronted, off when public — see edge proxy-protocol on|off|status), the client-IP attribution keys trusted_proxy_cidrs / client_ip_header / trust_loopback_client_ip_header, allow_push_update (opt in to cloud-initiated push updates; default false), the optional buffer profile buffer_stream/buffer_session/buffer_frame (byte counts, or k/m/g suffixes), and the operator binary-path overrides bin_path / bin_<tool>. Read by run; serve flags override per key (where a flag exists). # comments and blank lines are preserved. Read/write it with edge cli config get|set |
lan-cert/cert.pem, lan-cert/key.pem | The long-lived self-signed LAN TLS cert nginx terminates on the LAN port; its SHA-256 fingerprint is pinned in client/gateway blobs. There is no rotate flag — to force a new one, delete this directory and re-run sudo burrowee edge nginx reconcile --mode lan (see Rotating the LAN certificate) |
bridge/bridge_ed.key | This edge's edge-to-edge bridge identity — separate from its relay identity above; generated automatically the first time the edge runs after upgrading, so every edge becomes bridge-capable with no setup step |
bridge/authorized_keys | The inbound bridge allowlist: peer edges' bridge public keys this edge accepts Links from (edge cli bridge approve) |
bridge/links.json | Operator-staged outbound bridge Links this edge subscribes to (edge cli bridge subscribe) |
Data root — /usr/local/burrowee/var/edge/
| File / dir | What it holds |
|---|---|
config.json | The latest console-signed relay config (owner tenant, authorized gateway fingerprints, served domains) — cached so status works offline; its signature is verified on every read |
logs/ | Service logs (every stderr line timestamped) |
stats/ | Persisted daily-stats series |
nginx front
burrowee edge nginx writes server-only snippets and wires them in — it never rewrites your existing servers (the whole nginx verb family self-elevates via sudo where needed). Where the snippets themselves land differs by platform: on Linux they sit inside the resolved nginx conf dir (<nginx-conf-dir> below — nginx -V's own --conf-path, not an assumed constant); on macOS they sit in burrowee's own root-owned tree, /usr/local/burrowee/etc/nginx/, kept out of whichever package manager's (or hand-built) conf dir is actually running nginx — see nginx on macOS. The frontier and LAN fronts are two separate files in the same stream include folder, distinguished by filename (see nginx front → File paths):
| Path | Purpose |
|---|---|
<nginx-conf-dir>/servers-stream/burrowee-edge-stream.conf (Linux) — /usr/local/burrowee/etc/nginx/servers-stream/burrowee-edge-stream.conf (macOS) | The frontier stream front (nginx install/reconcile --mode frontier, and the legacy apply's combined file): :443 ssl_preread SNI passthrough to the edge's loopback tls_listen |
<nginx-conf-dir>/servers-stream/burrowee-edge-lan.conf (Linux) — /usr/local/burrowee/etc/nginx/servers-stream/burrowee-edge-lan.conf (macOS) | The LAN front (reconcile --mode lan): an L4 stream server — listen 8448 ssl; — terminating TLS with the LAN cert and passing the byte stream straight through to the edge's loopback lan_listen. Lives in the same servers-stream/ folder as the frontier front (needs libnginx-mod-stream on Debian/Ubuntu, same as the frontier front), so it needs no extra hook |
<nginx-conf-dir>/nginx.conf (Linux) — the running nginx's own nginx.conf (macOS) | Gains one top-level line if missing (frontier only): a relative stream { include servers-stream/*.conf; } on Linux, an absolute stream { include /usr/local/burrowee/etc/nginx/servers-stream/*.conf; } on macOS — pointing at burrowee's tree rather than the package manager's |
Service unit
Installed by burrowee edge service install — system-level units for the edge and its updater. service status still reports legacy per-user units; --force-service-override consents to replacing a unit installed by a different user.
| Platform | Unit | Path |
|---|---|---|
| macOS (launchd daemons) | com.burrowee.edge, com.burrowee.edge.updater | /Library/LaunchDaemons/ |
| Linux (systemd system units) | burrowee-edge.service, burrowee-edge-updater.service | /etc/systemd/system/ |