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
Merged
Conversation
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a Tailscale tunnel comes up, the webui automatically runs
tailscale serve --bg 8787to bind the tailnet HTTPS URL to localhost:8787. That call can fail in two scenarios — both invisible to the user prior to this PR:tailscale servereturns "Serve is not enabled on your tailnet". The webui logged this at DEBUG level and silently dropped it.start_upflow is never invoked, so its post-authconfigure_servehook 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)serve_state(idle/ok/error) +serve_errorfields to_up_state. Included in both/api/tailscale/statusand/api/tailscale/up/pollresponses.configure_serve()in_attempt_configure_serve(attempt_id?)— single channel for state writes, gated byattempt_idto match the existing stale-thread guard forstate=updates.start_upafterrc=0andBackendState=Running(existing webui Connect path)get_up_progresson mid-poll Running detection (covers desktop-app auth)handle_post_serve(manual retry button — see below)logout().Frontend (
static/panels.js+static/index.html)#tsServeStatediv in the Tailscale tile renders only when connected.state.serve_state:ok— "HTTPS configured ✓"error— "Configure HTTPS" button + the specific error messageidle— "Configure HTTPS" button + neutral hint pointing at the admin-console HTTPS toggle (so users who authed via desktop app always have a recovery affordance)POST /api/tailscale/serveand re-fetches/api/tailscale/statusto update the rendered state.Test plan
python3 -c "import api.tailscale ..."smoke imports cleanly with serve fields on_up_stateserve_state=okif HTTPS is enabled in tailnet,serve_state=errorwith admin-console hint if notAfter merge, FITB main repo bumps
forks/hermes-webuito consume.