Appearance
nginx front
nginx fronts whichever port the current serve mode needs, since the edge itself binds only loopback or unprivileged ports. You rarely run this by hand: burrowee edge cli bootstrap and burrowee edge mode reconcile it for you automatically, and burrowee edge doctor --fix repairs it. This page is for understanding what's on disk and for manual repair.
sh
burrowee edge nginx install|uninstall|apply|reconcile --mode frontier|lanAll four subcommands resolve the conf dir from the nginx that's actually running — nginx -V's own --conf-path, never an assumed platform path — and self-elevate under sudo when run unprivileged, so you don't need to prefix sudo yourself; the same goes for mode, bootstrap, and proxy-protocol, which run an nginx reconcile of their own. On Linux that resolves to /etc/nginx on a stock install. On macOS burrowee's own fronts never land inside whichever package manager's conf dir is in play (Homebrew, MacPorts, or a hand-built root nginx's own tree) — they live in a separate root-owned tree, /usr/local/burrowee/etc/nginx/, that burrowee itself creates and owns — so macOS elevates exactly the way Linux does. See nginx on macOS for why the tree is separate and what the three layouts look like.
nginx install — the public SNI front
For a frontier edge. Writes an ssl_preread SNI-routing front: nginx inspects the TLS handshake's SNI name and proxies the raw bytes to the edge's loopback tls_listen port — it never terminates TLS and never touches a certificate. The edge's own certificates (this host's own cert plus every console-pushed custom-domain cert) all serve from behind this one front.
sh
sudo burrowee edge nginx installRequires host_fqdn to already be set — burrowee edge cert issue and the bootstrap prompt both set it when they run. In order it:
- reads
host_fqdnplus this edge's custom + random served domains from the signed console config, and builds the SNI match set (each domain as a literal, one~^.+\.<apex>$regex per random-domain apex), - writes the map + a
listen 443; ssl_preread on;stream server to the snippet path (below), - wires the include into
nginx.confif it isn't already, - reloads (or starts) nginx, then verifies the front actually answers on
:443— locally and through the public internet — instead of finishing silently. (doctor's own--no-externalflag skips that second probe when you run it from there instead — see Operations.)
✓ host front config :443 → 127.0.0.1:9443
✓ host front local :443 listening
✓ host front external https://edge.example.com reachable (426)Flags: --home <dir> (a non-default config root — the machine-owned default needs no flag, even under sudo), --conf-dir <dir> (default /etc/nginx on Linux, /opt/homebrew/etc/nginx on macOS), --internal-port <port> (the loopback port nginx proxies to — defaults to whatever tls_listen currently resolves to, so a bare install reconciles rather than clobbering a console-pushed port).
When run under sudo on Linux, install also drops a narrow passwordless-sudo rule scoped to exactly the service user and the nginx-reconcile command, and prints:
installed passwordless nginx-reconcile rule for user "edge"That rule is what lets the unprivileged edge daemon reconcile the root-owned front on every console-pushed domain/port change without a manual doctor --fix (see Operations → keeping the front in sync). Run install without sudo and it skips the rule (printing a note to re-run under sudo); nginx uninstall removes it again.
nginx reconcile --mode frontier|lan — the mode-aware form
This is what bootstrap and burrowee edge mode actually call. It installs the front the given mode needs and tears down the other mode's leftover front, so the two never coexist on disk:
--mode frontier— runs the equivalent ofnginx install, then best-effort removes a stale LAN front.--mode lan— sets up the LAN front below, then best-effort removes a stale frontier front.
With no --mode flag it derives the mode from the signed console config. doctor --fix and the daemon's own config-apply hook (when the console pushes a tls_listen/mode change) both shell out to this command — see Operations → keeping the front in sync.
The LAN front
A LAN edge needs nginx to own the externally-visible port and terminate TLS, since the edge itself only ever binds a plain loopback WebSocket. nginx reconcile --mode lan (or nginx apply, below) handles it:
- ensures the LAN certificate exists — a 10-year self-signed cert generated once at
lan-cert/under the edge config root (/usr/local/etc/burrowee/edge/lan-cert/on a system install) and never touched again unless you delete it (see rotating it), - writes an L4
streamserver —listen 8448 ssl;terminating TLS with the LAN cert and passing the byte stream through to the edge's loopbacklan_listen— into the snippet path (below); a plain stream conversion is what lets server-first protocols (VNC, say) work through a LAN edge, - reloads (or starts) nginx, and prints the pin:
LAN cert fingerprint: <sha256>
pin distributed via the next endpoint reportGateways pick the pin up automatically from the edge's self-reported endpoints; CLI clients get it inside the relay blob they paste — nothing to distribute by hand for either.
nginx uninstall — tearing a front down
sh
sudo burrowee edge nginx uninstall # remove the frontier stream front
sudo burrowee edge nginx uninstall --lan # remove the LAN front insteadRemoves the matching snippet file and reloads nginx (a missing snippet is a no-op). It leaves the include hook in nginx.conf in place — a clean, empty hook — and never touches tls_listen/host_fqdn/the host cert/lan_cert in the edge's own config.
File paths
The frontier front and the LAN front are two separate files in the same stream include folder, distinguished by filename. Where that folder actually is differs by platform:
| Platform | Frontier | LAN |
|---|---|---|
| Linux | <conf-dir>/servers-stream/burrowee-edge-stream.conf | <conf-dir>/servers-stream/burrowee-edge-lan.conf |
| macOS | /usr/local/burrowee/etc/nginx/servers-stream/burrowee-edge-stream.conf | /usr/local/burrowee/etc/nginx/servers-stream/burrowee-edge-lan.conf |
On Linux, <conf-dir> is whatever nginx -V resolves (/etc/nginx on a stock install). On macOS the two snippets never land inside Homebrew's, MacPorts', or a hand-built nginx's own conf dir — they live in burrowee's own root-owned tree instead, so brew upgrade nginx (or the MacPorts/hand-built equivalents) never contends with burrowee for the same directory. See nginx on macOS.
Both files live in a stream {} context — install and apply idempotently ensure a top-level stream { include .../servers-stream/*.conf; } hook in nginx.conf (a relative include on Linux, an absolute one pointing at burrowee's own tree on macOS), or just inject the include line if a stream {} block already exists there. (The classic trap: many distros include conf.d/*.conf from inside http {}, where a stream {} block would be silently dead — the include must sit at the top level. Confirm nginx -V lists --with-stream.)
Rotating the LAN certificate
There's no rotate flag — the LAN cert is generated once and left alone, since clients pin its fingerprint. To force a new one: stop the service, delete the lan-cert/ directory under the edge config root (or wherever lan_cert in the config points), and re-run burrowee edge nginx reconcile --mode lan to regenerate it, then restart.
Treat this as a deliberate operator act, not routine hygiene — the cert is good for 10 years:
- Gateways heal automatically — the new pin goes out in the edge's next endpoint report.
- CLI clients do not. A CLI gets the pin inside the relay blob it pasted, and there is no push channel to update it — every CLI using this edge needs its relay blob re-pasted after a rotation.
The apply command
sh
sudo burrowee edge nginx apply [--listen-tls <port>] [--listen-lan <port>] [--print]Predates the install/reconcile split and still works for back-compat or manual use: it renders and loads the passthrough front — a plain :443 TCP passthrough to the edge's TLS port (never terminating TLS itself; that still happens inside the edge, with the console-pushed certificates) alongside the LAN block, both in stream {} context. Like install, it ensures the top-level stream { include servers-stream/*.conf; } hook and reloads nginx, so what it writes is actually served. --print previews the rendered config on stdout with no writes and no certificate generation. Defaults: --listen-tls 443, --listen-lan 8448.
Prefer install/reconcile --mode for anything new — they're what bootstrap, mode, and doctor --fix use, and they keep the SNI-only frontier front (no certificate exposure to nginx) that apply's combined passthrough doesn't provide.
PROXY protocol
With nginx in front, the TCP connection the edge sees comes from loopback — so the front sends the PROXY protocol header, and the real client IP survives into the edge's connection stats. It has its own verb:
sh
burrowee edge proxy-protocol status # print the effective value and where it came from
burrowee edge proxy-protocol on # send the PROXY header from the nginx front
burrowee edge proxy-protocol off # stop sending itThe default is derived: on when tls_listen is loopback (nginx-fronted), off when it is public (the edge binding its own socket — nothing in between to preserve the IP). on/off write the proxy_protocol config key, reconcile the nginx front to match, and restart, so the two sides can never disagree. If you run your own front instead of the managed one, the client-IP attribution keys trusted_proxy_cidrs, client_ip_header, and trust_loopback_client_ip_header in the edge config cover that case.
Port preflight
Before writing anything, apply probes its external ports (--listen-tls, --listen-lan). A port already held by nginx serving this same snippet is fine — re-applying is idempotent. A port held by anything else fails fast, naming the holder and the right flag to pick a different one, so a conflict never leaves a broken snippet on disk:
✗ port 8448 is already in use by another process (held by caddy pid 1234).
Pick a different port and re-apply the nginx front with a different --listen-lan value.
(and set lan_listen=127.0.0.1:<local-port> + lan_advertise_port=<nginx-port> in the edge config)QUIC is not fronted
If you enable a QUIC listener (quic_addr in the config), it is UDP — none of these fronts carry it. The edge binds it directly.