[Bug]: --tailscale-serve leaves headless backend classified as local-only
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
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/server
Steps to reproduce
-
Start T3 Code:
npx t3@nightly serve --tailscale-serve --tailscale-serve-port 443 -
Confirm that T3 reports both:
Listening on http://127.0.0.1:3773
Tailscale Serve configured -
Open the Tailscale Serve URL from another device:
https://<machine>.<tailnet>.ts.net -
Navigate to Settings → Connections.
-
Attempt to manage remote pairing or authorized clients.
Expected behavior
A backend exposed through --tailscale-serve should be treated as remotely reachable.
Settings → Connections should allow pairing links and authorized clients to be managed while the
underlying HTTP server remains bound securely to 127.0.0.1.
Actual behavior
Settings → Connections reports:
This backend is only reachable on this machine. Restart it with a non-loopback host to enable remote
pairing.
The remote pairing and authorized-client controls are unavailable, even though the backend is reachable
through its Tailscale Serve HTTPS URL.
The apparent cause is that EnvironmentAuthPolicy.ts determines remote reachability solely from the
bind host:
const isRemoteReachable = isWildcardHost(config.host) || !isLoopbackHost(config.host);
For a headless browser, ConnectionsSettings.tsx then relies on that policy:
const isLocalBackendNetworkAccessible = currentAuthPolicy === "remote-reachable";
Unlike the desktop application, the headless browser has no desktopBridge providing Tailscale endpoint
discovery.
It may be appropriate for tailscaleServeEnabled to affect the server auth policy:
const isRemoteReachable =
config.tailscaleServeEnabled ||
isWildcardHost(config.host) ||
!isLoopbackHost(config.host);
Related but distinct: #2834 concerns advertising the Tailscale HTTPS URL in headless pairing output.
Impact
Major degradation or frequent failure
Version or commit
0.0.29-nightly.20260724.893 / ece05087a70e94efcd57441337fa1249559362b
Environment
NixOS, Chromium-based browser, Tailscale 1.98.5, Node.js 24.15.0, npm 11.12.1
Logs or stack traces
INFO: Listening on http://127.0.0.1:3773
INFO: Tailscale Serve configured
{ localPort: 3773, servePort: 443 }
T3 Code server is ready.
Connection string: http://localhost:3773
Screenshots, recordings, or supporting files
No response
Workaround
Starting T3 with --host 0.0.0.0 causes it to use the remote-reachable auth policy and enables the
pairing controls:
npx t3@nightly serve \
--host 0.0.0.0 \
--tailscale-serve \
--tailscale-serve-port 443
However, this unnecessarily binds port 3773 to every network interface and requires the host firewall to
prevent direct access. The preferred behavior is to retain the loopback bind and expose the backend only
through Tailscale Serve.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with EnvironmentAuthPolicy.ts and trace how the bind host determines the remote-reachable policy, then inspect ConnectionsSettings.tsx to see how that policy controls pairing and authorized-client actions. Reproduce with --tailscale-serve on a loopback bind and verify that the controls become available without requiring --host 0.0.0.0.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- authentication, backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100