Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/web
Steps to reproduce
- Scratch test run against the server's classifier, placed next to
apps/server/src/auth/EnvironmentAuthPolicy.tsand run withnode_modules/.bin/vp test run --silent=false apps/server/src/auth/<scratch>.test.ts:
import { describe, expect, it } from "vite-plus/test";
import { resolveServerAuthPolicy } from "./EnvironmentAuthPolicy.ts";
describe("tailscale serve auth policy", () => {
it("t3 serve --tailscale-serve (no --host, no --lan) is classified loopback-browser", () => {
const policy = resolveServerAuthPolicy({ mode: "web", host: undefined });
console.log(`policy for mode=web host=undefined: ${policy}`);
expect(policy).toBe("loopback-browser");
});
});- Reported path, not run here (no Tailscale on the test machine): on a tailnet with HTTPS certificates enabled, run
t3 serve --tailscale-serve, pair a second device throughhttps://<machine>.<tailnet>.ts.net/, open Settings → Sharing & access in that device's browser, and read the Network access row.
The classifier result is deterministic for this configuration; the row text follows from the source lines cited above for every browser session with the maintain permission on such a server.
Expected behavior
docs/user/remote-access.md:169-186 documents t3 serve --tailscale-serve as the way to give a command-line server Tailscale HTTPS access, with pairing links at https://machine.tailnet.ts.net/. For a server published that way, the Network access row should not say that only this machine can connect, should not show remote access as off, and should not advise restarting on a non-loopback host to enable remote pairing; it should reflect that the server is reachable from the tailnet through Tailscale HTTPS. The open PR #10083 states the same expectation for this row.
Actual behavior
Source-only for the rendered row; the server classification it depends on was reproduced by a run. A command-line server started as documented for Tailscale HTTPS, t3 serve --tailscale-serve, keeps its listener on loopback and reaches the tailnet through Tailscale Serve's https://<machine>.<tailnet>.ts.net proxy to http://127.0.0.1:<port>. The server classifies that configuration as auth policy loopback-browser, because resolveServerAuthPolicy looks only at the bind host (apps/server/src/auth/EnvironmentAuthPolicy.ts:22-26) and the default host for t3 serve without --host or --lan is undefined, which means 127.0.0.1 (apps/server/src/cli/config.ts:441-443). In a browser client (no desktop bridge) with a session that has the environment maintain permission, Settings → Sharing & access renders renderDisabledNetworkAccessRow for that server (apps/web/src/components/settings/ConnectionsSettings.tsx:1225-1233). For policy loopback-browser that row says "Only this machine can connect. Restart with a non-loopback host for remote pairing." and shows the Network access switch off (apps/web/src/components/settings/ConnectionsSettings.tsx:1095-1115, with isLocalBackendNetworkAccessible false at :440-442). The user sees this while reading the page from another device over the Tailscale HTTPS URL, so the row contradicts the connection they are using, and its advice to restart on a non-loopback host would expose the plain-HTTP listener on every interface even though Tailscale HTTPS pairing already works.
Impact and scope: Impact: P3 - the row shows the wrong state and misleading advice; pairing and client management keep working because they are gated on session permissions, not this row.
Affects browser clients of command-line servers started with --tailscale-serve and without --host or --lan. Following the row's advice (restarting with --host 0.0.0.0 or --lan) is unnecessary and widens the plain-HTTP listener to every interface. Desktop clients are not affected, since they render the desktop Network access and Tailscale HTTPS rows instead. Workaround: ignore the row; Tailscale HTTPS pairing works as is.
Impact
Cosmetic issue
Version or commit
main @ 86ff9d0
Environment
Scratch test run with the repository's Vite+ test runner (Vitest 5.0.5) on Linux x64. The row itself is platform-independent web UI.
Logs or stack traces
Scratch test output (run as above):
stdout | src/auth/zzrepro-ui-authpolicy.test.ts > zzrepro ui auth policy > t3 serve --tailscale-serve (no --host, no --lan) is classified loopback-browser
policy for mode=web host=undefined: loopback-browser
Test Files 1 passed (1)
Tests 1 passed (1)
Source references at the pinned commit: apps/web/src/components/settings/ConnectionsSettings.tsx:1104 holds the row text "Only this machine can connect. Restart with a non-loopback host for remote pairing."; apps/server/src/auth/EnvironmentAuthPolicy.ts:26 returns loopback-browser for a non-desktop server on a loopback host; apps/server/src/cli/config.ts:441-443 leaves the host undefined for t3 serve without --host or --lan; packages/tailscale/src/tailscale.ts:452-453 runs tailscale serve --bg --https=<port> http://127.0.0.1:<localPort>, so Serve keeps the loopback listener reachable from the tailnet.
Screenshots, recordings, or supporting files
No response
Workaround
See Impact and scope under Actual behavior.
Additional details
- Interface: UI: Settings → Sharing & access, Network access row (browser client)
- Earliest failure stage: Output or presentation
Additional context
The server descriptor carries no Tailscale Serve signal today (ServerAuthDescriptor and ServerConfig in packages/contracts/src have no Serve field), so the web row has no input that distinguishes this server from a truly local-only one. The fix may therefore cross apps/server and apps/web, as PR #10083 does on the server side.
References
#4462 (closed by its reporter as no longer seen; it reported the same loopback classification hiding pairing controls, which are now gated on session permissions, so this report covers only the Network access row that still shows the wrong state and advice); open PR #10083 changes the server's auth policy for Serve and awaits maintainer approval, with no open issue tracking the symptom; #25348 (open, CLI prints a localhost pairing URL for the same server, a different surface); #16238 (open, Serve setup failures are silent, a different failure).
Found by reading T3 Code's Tailscale integration against the Tailscale source (tailscale/tailscale@071bf947, v1.105.0); written up with AI assistance (Claude Code).
Activity
fix(web): Settings shows network access on only once Tailscale Serve …