fix(installer): dedicate Tailscale listener port
This commit is contained in:
+8
-6
@@ -734,8 +734,9 @@ cat > "$TS_SHIM_PATH" <<SHIM
|
||||
#
|
||||
# Usage:
|
||||
# hermes-relay-tailscale status
|
||||
# hermes-relay-tailscale enable [--dashboard-listener-port 443] [--dashboard-target-port 9119] [--api-port 8642] [--no-api]
|
||||
# hermes-relay-tailscale disable [--dashboard-listener-port 443] [--api-port 8642] [--no-api]
|
||||
# hermes-relay-tailscale enable [--dashboard-listener-port 10443] [--dashboard-target-port 9119] [--api-port 8642] [--no-api]
|
||||
# hermes-relay-tailscale disable [--dashboard-listener-port 10443] [--dashboard-target-port 9119] [--api-port 8642] [--no-api]
|
||||
# hermes-relay-tailscale enable --dashboard-listener-port 443 # advanced override; only when :443 is free
|
||||
# hermes-relay-tailscale enable --port 8767 # explicit legacy/direct Relay
|
||||
# hermes-relay-tailscale disable --port 8767 # explicit legacy/direct Relay
|
||||
#
|
||||
@@ -843,7 +844,7 @@ fi
|
||||
|
||||
# ── 7/7 Offer (don't force) Tailscale serve enablement ───────────────────
|
||||
# ADR 25 — first-class Tailscale helper. The relay stays loopback-bound on
|
||||
# :8767 while the recommended Tailscale ingress listens on HTTPS :443 and
|
||||
# :8767 while the recommended Tailscale ingress listens on HTTPS :10443 and
|
||||
# proxies local Dashboard :9119; Relay rides Dashboard's same-origin plugin
|
||||
# transport. The optional Hermes API server may also be published on :8642
|
||||
# for headless compatibility.
|
||||
@@ -879,7 +880,7 @@ if command -v tailscale >/dev/null 2>&1; then
|
||||
else
|
||||
printf "\n"
|
||||
printf " ${C_DIM}%s${C_RESET} %s\n" "$SYM_INFO" "Tailscale is installed. Publish Dashboard + optional API over your tailnet?"
|
||||
printf " ${C_DIM}%s${C_RESET} %s\n" "$SYM_INFO" "Runs HTTPS ${C_BOLD}:443${C_RESET} → local Dashboard ${C_BOLD}:9119${C_RESET} (including Relay path), plus ${C_BOLD}:8642${C_RESET} for optional API fallback."
|
||||
printf " ${C_DIM}%s${C_RESET} %s\n" "$SYM_INFO" "Runs dedicated HTTPS ${C_BOLD}:10443${C_RESET} → local Dashboard ${C_BOLD}:9119${C_RESET} (including Relay path), plus ${C_BOLD}:8642${C_RESET} for optional API fallback."
|
||||
printf " ${C_DIM}%s${C_RESET} %s\n" "$SYM_INFO" "Loopback services stay private; Tailscale handles TLS + identity."
|
||||
printf "\n ${C_BOLD}Enable now?${C_RESET} ${C_DIM}[y/N]${C_RESET} "
|
||||
read -r ts_reply </dev/tty || ts_reply=""
|
||||
@@ -891,7 +892,7 @@ if command -v tailscale >/dev/null 2>&1; then
|
||||
|
||||
if [ -n "$ts_do" ]; then
|
||||
if "$VENV_PY" -m plugin.relay.tailscale_cli enable >/dev/null 2>&1; then
|
||||
ok "tailscale serve enabled on HTTPS :443 for local Dashboard :9119, plus optional API :8642"
|
||||
ok "tailscale serve enabled on HTTPS :10443 for local Dashboard :9119, plus optional API :8642"
|
||||
info " Check: ${C_BOLD}hermes-relay-tailscale status${C_RESET}"
|
||||
info " Revoke: ${C_BOLD}hermes-relay-tailscale disable${C_RESET}"
|
||||
else
|
||||
@@ -967,7 +968,8 @@ printf " ${C_DIM}%s${C_RESET} ${C_BOLD}hermes-pair --mode auto --prefer tails
|
||||
printf " ${C_DIM}%s${C_RESET} ${C_BOLD}hermes-status${C_RESET} ${C_DIM}# show live phone state${C_RESET}\n" "$SYM_INFO"
|
||||
printf "\n"
|
||||
printf " ${C_BOLD}${C_CYAN}Remote access${C_RESET}\n"
|
||||
printf " ${C_DIM}%s${C_RESET} ${C_BOLD}hermes-relay-tailscale enable${C_RESET} ${C_DIM}# HTTPS :443 → Dashboard :9119 + optional API :8642${C_RESET}\n" "$SYM_INFO"
|
||||
printf " ${C_DIM}%s${C_RESET} ${C_BOLD}hermes-relay-tailscale enable${C_RESET} ${C_DIM}# HTTPS :10443 → Dashboard :9119 + optional API :8642${C_RESET}\n" "$SYM_INFO"
|
||||
printf " ${C_DIM}%s${C_RESET} ${C_BOLD}hermes-relay-tailscale enable --dashboard-listener-port 443${C_RESET} ${C_DIM}# advanced override; only if :443 is free${C_RESET}\n" "$SYM_INFO"
|
||||
printf " ${C_DIM}%s${C_RESET} ${C_BOLD}hermes-relay-tailscale enable --port 8767${C_RESET} ${C_DIM}# legacy/direct Relay only${C_RESET}\n" "$SYM_INFO"
|
||||
printf " ${C_DIM}%s${C_RESET} ${C_BOLD}hermes-relay-tailscale status${C_RESET} ${C_DIM}# show served Tailscale ports${C_RESET}\n" "$SYM_INFO"
|
||||
printf "\n"
|
||||
|
||||
@@ -23,16 +23,26 @@ class InstallTailscaleContractTests(unittest.TestCase):
|
||||
self.script,
|
||||
)
|
||||
self.assertIn(
|
||||
"HTTPS :443 for local Dashboard :9119, plus optional API :8642",
|
||||
"HTTPS :10443 for local Dashboard :9119, plus optional API :8642",
|
||||
self.script,
|
||||
)
|
||||
|
||||
def test_installed_shim_marks_direct_relay_as_explicit_legacy(self) -> None:
|
||||
self.assertIn(
|
||||
"hermes-relay-tailscale enable [--dashboard-listener-port 443] "
|
||||
"hermes-relay-tailscale enable [--dashboard-listener-port 10443] "
|
||||
"[--dashboard-target-port 9119] [--api-port 8642] [--no-api]",
|
||||
self.script,
|
||||
)
|
||||
self.assertIn(
|
||||
"hermes-relay-tailscale disable [--dashboard-listener-port 10443] "
|
||||
"[--dashboard-target-port 9119] [--api-port 8642] [--no-api]",
|
||||
self.script,
|
||||
)
|
||||
self.assertIn(
|
||||
"hermes-relay-tailscale enable --dashboard-listener-port 443 "
|
||||
"# advanced override; only when :443 is free",
|
||||
self.script,
|
||||
)
|
||||
self.assertIn(
|
||||
"hermes-relay-tailscale enable --port 8767 # explicit legacy/direct Relay",
|
||||
self.script,
|
||||
@@ -48,7 +58,12 @@ class InstallTailscaleContractTests(unittest.TestCase):
|
||||
)[1].split(
|
||||
'${C_BOLD}${C_CYAN}Self-setup / troubleshoot${C_RESET}', 1
|
||||
)[0]
|
||||
self.assertIn("HTTPS :443 → Dashboard :9119 + optional API :8642", remote_access)
|
||||
self.assertIn("HTTPS :10443 → Dashboard :9119 + optional API :8642", remote_access)
|
||||
self.assertIn(
|
||||
"enable --dashboard-listener-port 443${C_RESET} "
|
||||
"${C_DIM}# advanced override; only if :443 is free",
|
||||
remote_access,
|
||||
)
|
||||
self.assertIn("legacy/direct Relay only", remote_access)
|
||||
self.assertNotIn("publish relay :8767", remote_access.lower())
|
||||
self.assertNotIn("--https=9119", remote_access)
|
||||
|
||||
@@ -40,8 +40,9 @@ class PairCliSurfaceTests(unittest.TestCase):
|
||||
).read_text(encoding="utf-8")
|
||||
|
||||
self.assertIn("--dashboard-url", skill)
|
||||
self.assertIn("Tailscale Serve normally exposes HTTPS `443`", skill)
|
||||
self.assertIn("Tailscale Serve normally exposes dedicated HTTPS `10443`", skill)
|
||||
self.assertIn("local Dashboard on `9119`", skill)
|
||||
self.assertIn("Listener `443` is an advanced explicit override", skill)
|
||||
self.assertIn("LAN/raw-tailnet Dashboard candidates on\n `9119`", skill)
|
||||
self.assertIn("--legacy-direct-relay", skill)
|
||||
self.assertIn("does not imply or expose public port `8767`", skill)
|
||||
|
||||
@@ -36,7 +36,7 @@ Operators with the Hermes dashboard open can also mint the same QR from the web
|
||||
|
||||
1. **Hermes-Relay plugin installed into the Hermes venv.** Verify by running `python -m plugin.pair --help` — if it errors with `ModuleNotFoundError: No module named 'plugin'`, install it first: `pip install -e <path-to-hermes-relay-repo>`.
|
||||
2. **Hermes API server reachable** on `API_SERVER_HOST:API_SERVER_PORT` (default `127.0.0.1:8642`). `plugin.pair` auto-reads this from `~/.hermes/config.yaml` → `~/.hermes/.env` → env vars → defaults.
|
||||
3. **Relay server running** on `RELAY_HOST:RELAY_PORT` (default `0.0.0.0:8767`) if the user wants terminal/bridge channels. The Relay may stay host-internal: current Android pairing normally reaches it through the Dashboard's same-origin plugin transport. Tailscale Serve normally exposes HTTPS `443` and proxies the host-local Dashboard on `9119`; a raw LAN/tailnet route may reach `9119` directly. Without a live relay, the QR will configure chat only.
|
||||
3. **Relay server running** on `RELAY_HOST:RELAY_PORT` (default `0.0.0.0:8767`) if the user wants terminal/bridge channels. The Relay may stay host-internal: current Android pairing normally reaches it through the Dashboard's same-origin plugin transport. Tailscale Serve normally exposes dedicated HTTPS `10443` and proxies the host-local Dashboard on `9119`; a raw LAN/tailnet route may reach `9119` directly. Listener `443` is an advanced explicit override only when it is free. Without a live relay, the QR will configure chat only.
|
||||
4. **Host is Linux or macOS.** The relay uses a real PTY backend, which is POSIX-only. Windows hosts can generate API-only QRs but the terminal channel will not work.
|
||||
|
||||
## Procedure
|
||||
@@ -60,9 +60,10 @@ Operators with the Hermes dashboard open can also mint the same QR from the web
|
||||
A trusted configured `HERMES_DASHBOARD_PUBLIC_URL` / Dashboard public URL is
|
||||
also suitable. If no exact origin is available, omit the flag; the pair
|
||||
backend will construct conventional LAN/raw-tailnet Dashboard candidates on
|
||||
`9119`, or advertise the HTTPS `443` listener when Tailscale Serve maps it to
|
||||
local Dashboard `9119`. Never substitute the API server URL or infer public
|
||||
port `8767`.
|
||||
`9119`, or advertise the HTTPS `10443` listener when Tailscale Serve maps it
|
||||
to local Dashboard `9119`. HTTPS `443` is used only after the operator
|
||||
explicitly selects that advanced listener and confirms it is free. Never
|
||||
substitute the API server URL or infer public port `8767`.
|
||||
|
||||
If `python` resolves to the wrong interpreter (plugin not found), use the Hermes venv explicitly:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user