From 32a60f0c6e2b9032b536b09bb223714f250f80ba Mon Sep 17 00:00:00 2001 From: Kaloyan Danchev Date: Tue, 3 Nov 2026 22:29:40 +0200 Subject: [PATCH] docs: Unraid as a Herdr machine, and why it needed a --via wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit herdr-core machine add kept failing with "core did not start within 5 s". Cause: hc puts its core socket under XDG_RUNTIME_DIR, which on Unraid is /run/user/0 — created and destroyed per login session by elogind. The socket vanished with the session that started the core, so later clients found an empty directory. The core itself kept running on an unlinked socket, and core.log stayed empty because the failure is client side. Fixed entirely on the Mac with a --via transport that pins XDG_RUNTIME_DIR=/var/run/herdr-rt. Nothing on the server was changed. The transport uses key auth on 192.168.10.20:422, not Tailscale SSH, since --via needs something that asks nothing and the default tailnet ACL demands periodic browser re-auth. Also records the reboot caveat (/ is RAM, so the remote hc binary is lost) with a go-script fix written up but not applied, and corrects the 192.168.31.0/24 note: that shim was created for a Pi-hole that AdGuard replaced. Co-Authored-By: Claude Opus 5 --- docs/09-TAILSCALE-VPN.md | 2 +- docs/14-HERDR-REMOTE-MACHINES.md | 99 ++++++++++++++++++++++++++++++++ docs/CHANGELOG.md | 6 ++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 docs/14-HERDR-REMOTE-MACHINES.md diff --git a/docs/09-TAILSCALE-VPN.md b/docs/09-TAILSCALE-VPN.md index 2923ef0..982547d 100644 --- a/docs/09-TAILSCALE-VPN.md +++ b/docs/09-TAILSCALE-VPN.md @@ -228,7 +228,7 @@ logged out since roughly May 2026 and was re-enrolled on 2026-11-03. | Pref | Value | Reason | |------|-------|--------| -| `--advertise-routes` | none | The old `192.168.31.0/24` advertisement was dropped. That subnet is only the macvlan shim (`br0-shim` holds `192.168.31.250/32` with one host route to `192.168.31.4`) — nothing reachable lives there. | +| `--advertise-routes` | none | The old `192.168.31.0/24` advertisement was dropped. That subnet is only the macvlan shim created in `/boot/config/go` for a Pi-hole at `192.168.31.4`. Pi-hole was replaced by AdGuard: there is no such container any more and the address is silent, so nothing reachable lives there. | | LAN subnet routing | not advertised | The MikroTik container is primary for `192.168.10.0/24`, `.20`, `.25`, `.30`. A second advertiser for a subnet Unraid itself sits on would create a routing conflict. | | `--advertise-exit-node` | on | Redundant with the hAP today, kept as a fallback on the 24/7 box. **Approved in the admin console 2026-11-03** — shows as `offers exit node` and appears in `tailscale exit-node list`. | | `--accept-routes` | **false** | Critical. Unraid is *on* `192.168.10.0/24`; accepting the hAP's route for its own subnet would loop. This is why `tailscale status` reports the health warning "Some peers are advertising routes but --accept-routes is false" — expected here, not a fault. | diff --git a/docs/14-HERDR-REMOTE-MACHINES.md b/docs/14-HERDR-REMOTE-MACHINES.md new file mode 100644 index 0000000..0669722 --- /dev/null +++ b/docs/14-HERDR-REMOTE-MACHINES.md @@ -0,0 +1,99 @@ +# Herdr (hc) Remote Machines — Unraid + +Herdr (`Herdr.app`, bundle `dev.herdr.app`, CLI `herdr-core` aka `hc`) runs +programs and coding agents in terminals that stay alive, including on remote +machines reached over SSH. The Unraid server is registered as the machine +`unraid`. + +Added 2026-11-03. + +## Registration + +The transport is a wrapper on the Mac, not a plain SSH target: + +```bash +herdr-core machine add --via ~/.local/bin/herdr-via-unraid --name unraid --install +``` + +``` +unraid | state: connected | host: xtrm-unraid | hc: 0.1.17 +``` + +Verify with `herdr-core exec --on unraid 'hostname'` → `XTRM-Unraid`. + +## Why a wrapper and not `machine add root@192.168.10.20:422` + +`hc` starts a core process (`herdr-core serve`) on the remote and talks to it +over a unix socket under `XDG_RUNTIME_DIR`. On Unraid that resolves to +`/run/user/0`, which **elogind creates and destroys per login session**. So: + +1. `machine add` opens an SSH session and starts the core. The socket lands in + `/run/user/0/herdr-core/default.sock`. +2. The session ends. elogind removes `/run/user/0`, taking the socket with it. +3. The next client connects in a new session, finds a fresh empty + `/run/user/0`, and fails with `core did not start within 5 s`. + +The core is not at fault — it keeps running, holding a socket that has been +unlinked from the filesystem. `core.log` stays 0 bytes because the failure is +client side. Unraid also warns `hc: no systemd user manager here: the core ends +with whatever started it`, which is why `hc` cannot supervise its own core here. + +The fix is to pin `XDG_RUNTIME_DIR` to a path that outlives a login session. +Doing it in the `--via` transport keeps the change on the Mac and leaves the +server's shell configuration untouched. + +`~/.local/bin/herdr-via-unraid`: + +```sh +#!/bin/sh +# Herdr appends the shell line to run as the last argument. +exec ssh -T -o BatchMode=yes -o ConnectTimeout=10 \ + -p 422 -i "$HOME/.ssh/id_ed25519_unraid" root@192.168.10.20 \ + "export XDG_RUNTIME_DIR=/var/run/herdr-rt; mkdir -p \"\$XDG_RUNTIME_DIR\" && chmod 700 \"\$XDG_RUNTIME_DIR\"; $*" +``` + +## Why the LAN address and not the Tailscale IP + +`--via` requires a transport that passes bytes untouched and **asks nothing**. +Tailscale SSH on `100.100.208.69` sits behind the default tailnet ACL +`action: "check"`, which demands browser re-authentication each period — fine +interactively, fatal for a long-lived Herdr connection. + +Key auth on `192.168.10.20:422` asks nothing, and from outside the LAN it still +travels over Tailscale via the MikroTik subnet router (see +`docs/09-TAILSCALE-VPN.md`). Changing that ACL rule to `accept` for +`autogroup:self` would make the `100.x` address usable here too. + +## Reboot persistence + +Unraid runs `/` from `rootfs` (RAM) and `/run` as tmpfs, so both of these are +lost on every reboot: + +| Path | Lost on reboot | Recovery | +|------|----------------|----------| +| `/var/run/herdr-rt` | yes | self-healing — the `--via` wrapper recreates it on every connection | +| `/root/.local/bin/herdr-core` | yes | **manual** — `herdr-core machine update`, or `machine add --install` again | + +To make the binary survive, stash it on the boot flash and restore it from the +`go` script, in the same style as the existing `install`/`cp` lines there: + +```bash +mkdir -p /boot/config/herdr +cp /root/.local/bin/herdr-core /boot/config/herdr/herdr-core +``` + +then append to `/boot/config/go`: + +```bash +# Herdr (hc) remote machines. Unraid runs / from RAM, so the hc binary installed +# by `herdr-core machine add --install` is lost on reboot. Restore it from /boot. +# The runtime dir is not restored here: the Mac-side --via wrapper exports +# XDG_RUNTIME_DIR=/var/run/herdr-rt and creates it on every connection, because +# the default /run/user/0 is destroyed per login session by elogind. +mkdir -p /root/.local/bin +install -m 755 /boot/config/herdr/herdr-core /root/.local/bin/herdr-core 2>/dev/null +``` + +`install -m 755` matters: `/boot` is FAT32 and does not carry the execute bit. + +**Status: not applied.** Pending. diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 7d5dc7e..05ccee1 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,6 +13,12 @@ - **[SERVICE]** Exit node advertised from Unraid as a fallback to the hAP, and approved in the Tailscale admin console the same day. The tailnet now has two exit nodes: `mikrotik-tailscale` (100.74.219.35, primary) and `xtrm-unraid` (100.100.208.69, fallback). Neither has been exercised in anger from the Mac — without `--exit-node-allow-lan-access` an exit node cuts the client's own LAN access. - Detail, including the root-only `AllowTcpForwarding` behaviour in Unraid's stock sshd config, in `docs/09-TAILSCALE-VPN.md`. +### Tooling: Unraid registered as a Herdr (hc) machine +- **[SERVICE]** Unraid added to Herdr as the machine `unraid` (`hc` 0.1.17 on the remote). `herdr-core machine add` had been failing with `core did not start within 5 s`: `hc` puts its core socket under `XDG_RUNTIME_DIR`, which on Unraid is `/run/user/0` — a directory elogind creates and destroys per login session, so the socket disappeared the moment the session that started the core ended. The core kept running with an unlinked socket, and `core.log` stayed empty because the failure is client side. +- **[SERVICE]** Fixed from the Mac only, via `~/.local/bin/herdr-via-unraid`, a `--via` transport that exports `XDG_RUNTIME_DIR=/var/run/herdr-rt` on every connection. Nothing on the server was changed. Uses key auth on 192.168.10.20:422 rather than Tailscale SSH, because `--via` needs a transport that asks nothing and the default tailnet ACL `check` would demand periodic browser re-auth. +- **[SERVICE]** Reboot caveat: `/` is rootfs (RAM) and `/run` is tmpfs on Unraid, so `/root/.local/bin/herdr-core` is lost at every boot and needs `herdr-core machine update` to restore. A `/boot/config/go` entry to restore it automatically is written up but **not applied**. Detail in `docs/14-HERDR-REMOTE-MACHINES.md`. +- Corrected the 192.168.31.0/24 note: the shim was created in the go script for a Pi-hole at 192.168.31.4, which AdGuard replaced. No such container exists and the address is silent. + --- ## 2026-10-16 - Home Assistant: `corridor-bt-proxy` (Olimex ESP32-POE-ISO) added to the ESPHome integration and running as an active Bluetooth proxy. Temporarily on hAP ax3 ether3, VLAN 10 (192.168.10.100); it moves to CAP XL ether2 (VLAN 30) when mounted.