deploy/hyperborea: production config, user unit, install script, README (wake block pending titan's MAC)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# crossbar on hyperborea
|
||||
|
||||
crossbar runs on **hyperborea** (Raspberry Pi, Debian 13, aarch64) as a `systemd --user` unit,
|
||||
bound to its tailnet address only. Clients on the tailnet reach it at
|
||||
|
||||
http://hyperborea.scylla-hammerhead.ts.net:7777/<route>/v1
|
||||
|
||||
Why hyperborea: it is always on, wired on titan's LAN segment (`192.168.88.154`, which
|
||||
wake-on-LAN needs — magic packets are L2 broadcast), and not itself an inference host, so a
|
||||
router rebuild or a sleeping titan never takes crossbar down with it.
|
||||
|
||||
## Files
|
||||
|
||||
| file | purpose |
|
||||
|---|---|
|
||||
| `crossbar.toml` | the production config: hosts titan/straylight/dixie with their configured models and `parallel`, the routes |
|
||||
| `crossbar.service` | the user unit (`/srv/crossbar`, `Restart=always`) |
|
||||
| `install.sh` | cross-compiles for arm64 on the machine you run it from, copies binary + config + unit, restarts, prints the hosts view |
|
||||
|
||||
On hyperborea: binary, config and SQLite database live in `/srv/crossbar/`; the unit is
|
||||
`~/.config/systemd/user/crossbar.service` (`loginctl` linger is on, so it survives logout).
|
||||
|
||||
## Install / upgrade
|
||||
|
||||
deploy/hyperborea/install.sh # from any checkout on a host with Go 1.26 and ssh to hyperborea
|
||||
|
||||
Re-running upgrades in place (binary is replaced atomically, the unit restarted; leases persist in
|
||||
the database). Config-only changes: edit `crossbar.toml`, re-run.
|
||||
|
||||
## Verify
|
||||
|
||||
curl -s http://hyperborea.scylla-hammerhead.ts.net:7777/_crossbar/hosts | jq .
|
||||
curl -s http://hyperborea.scylla-hammerhead.ts.net:7777/_crossbar/routes | jq .
|
||||
curl -s 'http://hyperborea.scylla-hammerhead.ts.net:7777/_crossbar/usage?by=route'
|
||||
ssh hyperborea journalctl --user -u crossbar -f
|
||||
|
||||
A cheap end-to-end check uses the `probe` route (dixie's 9B first):
|
||||
|
||||
curl -s -D - -X POST -H 'Content-Type: application/json' \
|
||||
-d '{"model":"ornith-1.5-9b-uncensored","max_tokens":8,"messages":[{"role":"user","content":"Reply with pong."}]}' \
|
||||
http://hyperborea.scylla-hammerhead.ts.net:7777/probe/v1/chat/completions
|
||||
|
||||
The response carries `X-Crossbar-Host` (which router served it) and `X-Crossbar-Lease`
|
||||
(`new` or `reused`).
|
||||
|
||||
## Pointing clients at it
|
||||
|
||||
OpenCode (project-local `opencode.json`, or the global one with a per-project route):
|
||||
|
||||
```jsonc
|
||||
"provider": { "crossbar": { "npm": "@ai-sdk/openai-compatible",
|
||||
"options": { "baseURL": "http://hyperborea.scylla-hammerhead.ts.net:7777/opencode-a/v1" },
|
||||
"models": { "ornith-1.5-35b-a3b": {} } } }
|
||||
```
|
||||
|
||||
Hermes (`custom_providers[].base_url`, and the same in `delegation`/`auxiliary` blocks):
|
||||
|
||||
base_url: http://hyperborea.scylla-hammerhead.ts.net:7777/hermes-straylight/v1
|
||||
|
||||
Routes must exist in `crossbar.toml`; an unknown first path segment is `404 unknown route`.
|
||||
**Known gap:** `PLAN.md`'s one-route-per-instance launcher (`CROSSBAR_ROUTE="$(basename "$PWD")-$$"`)
|
||||
needs a route *template* (e.g. `[routes."opencode-*"]`) that the code does not have yet; until
|
||||
then add each instance's route explicitly.
|
||||
|
||||
## Wake-on-LAN for titan
|
||||
|
||||
The `[hosts.titan.wake]` block is present but commented out until the MAC is settled. Titan is on
|
||||
Wi-Fi (active private address `5e:fc:f2:3f:23:6b`, hardware `60:3e:5f:33:6f:b8`) with its dock's
|
||||
three Ethernet ports (`d2:30:99:9a:ee:03/04/05`) unplugged. Wired + `womp 1` is the reliable path;
|
||||
magic-packet wake over Wi-Fi on Apple Silicon is not guaranteed and the private address may
|
||||
rotate. Broadcast address is `192.168.88.255:9`.
|
||||
|
||||
## Security notes
|
||||
|
||||
- The bind is the tailnet address; only tailnet members can reach it. `identity = "tailscale"`
|
||||
with per-route `peers` is available when a route should be limited to named nodes;
|
||||
`tailscale whois` already works unprivileged on hyperborea.
|
||||
- Plain HTTP over the tailnet is WireGuard-encrypted on the wire. Hermes agents' *terminal*
|
||||
calls to this URL may trip tirith's `plain_http_to_sink`; prefer the MagicDNS name (never the
|
||||
raw IP) and add a rule-scoped trust entry rather than `--broad` if a prompt recurs. Provider
|
||||
traffic from the OpenAI client library is not scanned by tirith.
|
||||
- Bodies are never logged or stored; the database holds leases and per-request accounting only.
|
||||
Reference in New Issue
Block a user