Skip to content
This repository was archived by the owner on May 18, 2026. It is now read-only.

fix(tailscale): surface Serve config state + manual retry button (FITB#122 #2) - #9

Merged
roadhero merged 1 commit into
masterfrom
fix/tailscale-serve-state-surfacing
May 6, 2026
Merged

roadhero merged 1 commit into
masterfrom
fix/tailscale-serve-state-surfacing

Conversation

@roadhero

@roadhero roadhero commented May 6, 2026

Copy link
Copy Markdown

Summary

When a Tailscale tunnel comes up, the webui automatically runs tailscale serve --bg 8787 to bind the tailnet HTTPS URL to localhost:8787. That call can fail in two scenarios — both invisible to the user prior to this PR:

  1. HTTPS not enabled on the tailnet (admin-console toggle). tailscale serve returns "Serve is not enabled on your tailnet". The webui logged this at DEBUG level and silently dropped it.
  2. User authes via the desktop Tailscale app (not via webui's Connect button). The webui's start_up flow is never invoked, so its post-auth configure_serve hook never fires.

Net effect on a real user (FITB#122 #2): Tailscale machine joins tailnet, but the HTTPS URL returns DNS_PROBE_FINISHED_NXDOMAIN. No error surface, no retry path.

Backend (api/tailscale.py)

  • Add serve_state (idle / ok / error) + serve_error fields to _up_state. Included in both /api/tailscale/status and /api/tailscale/up/poll responses.
  • Wrap configure_serve() in _attempt_configure_serve(attempt_id?) — single channel for state writes, gated by attempt_id to match the existing stale-thread guard for state= updates.
  • Call the helper from THREE paths so all auth flows converge:
    • start_up after rc=0 and BackendState=Running (existing webui Connect path)
    • get_up_progress on mid-poll Running detection (covers desktop-app auth)
    • handle_post_serve (manual retry button — see below)
  • Reset both fields on logout().

Frontend (static/panels.js + static/index.html)

  • New #tsServeState div in the Tailscale tile renders only when connected.
  • Renders into three states based on state.serve_state:
    • ok — "HTTPS configured ✓"
    • error — "Configure HTTPS" button + the specific error message
    • idle — "Configure HTTPS" button + neutral hint pointing at the admin-console HTTPS toggle (so users who authed via desktop app always have a recovery affordance)
  • Button calls existing POST /api/tailscale/serve and re-fetches /api/tailscale/status to update the rendered state.

Test plan

  • python3 -c "import api.tailscale ..." smoke imports cleanly with serve fields on _up_state
  • Build container with the patch, click Connect → auth → Running → expect serve_state=ok if HTTPS is enabled in tailnet, serve_state=error with admin-console hint if not
  • Disable HTTPS in tailnet admin → click Configure HTTPS → expect error + retry available
  • Re-enable HTTPS in tailnet admin → click Configure HTTPS → expect success
  • Auth via desktop Tailscale app (skip webui Connect) → open Settings → expect "Configure HTTPS" button visible (idle state) → click → success

After merge, FITB main repo bumps forks/hermes-webui to consume.

…B#122 #2)

Before: when Tailscale auth completed (whether via webui Connect button or
the desktop app), the webui's auto-`tailscale serve --bg 8787` could fail
silently. The most common failure mode is "Serve is not enabled on your
tailnet" — fixable by toggling HTTPS on at admin console, but the user
had no way to know that was the problem and no way to retry once they'd
fixed it. Result: Tailscale machine joins tailnet, but the HTTPS URL
returns DNS_PROBE_FINISHED_NXDOMAIN.

This bug also covered the case where the user authes via the desktop
Tailscale app: webui's start_up was never called, so its post-auth
configure_serve hook never fired at all.

The fix:

1. Add serve_state ("idle"|"ok"|"error") + serve_error fields to
   _up_state and include them in /api/tailscale/status.
2. Wrap configure_serve() in _attempt_configure_serve() — single channel
   for state writes, gated by attempt_id like the existing state= guard.
3. Call the helper from BOTH start_up (rc=0 + Running) AND
   get_up_progress (mid-poll Running detection — covers desktop-app
   auth path) AND handle_post_serve (manual retry).
4. Reset serve_state on logout.
5. Frontend renders a "Configure HTTPS" button under the Tailscale
   status whenever connected, alongside the error message when the last
   attempt failed. Clicking re-fires POST /api/tailscale/serve and
   loadTailscaleConnection() refreshes the rendered state.

The button is shown even on serve_state="idle" (e.g. user authed via
desktop app, no auto-attempt yet recorded) so users always have a
recovery path. On serve_state="ok" the button is replaced with a
checkmark; the user doesn't need to think about it once configured.

The underlying tailnet-side prerequisite (HTTPS toggle in admin console)
is unchanged — that's per-tailnet config, not a code bug. But now the
error surfaces clearly with a hint about where to enable it.
@roadhero
roadhero merged commit 929a7a8 into master May 6, 2026
0 of 3 checks passed
@roadhero
roadhero deleted the fix/tailscale-serve-state-surfacing branch May 6, 2026 13:27
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant