pingdotgg / pingdotgg/t3code

[Bug]: --tailscale-serve leaves headless backend classified as local-only

Open Beginner friendly
#4,462 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug needs-triage
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
  1. Start T3 Code:

    npx t3@nightly serve --tailscale-serve --tailscale-serve-port 443
    
  2. Confirm that T3 reports both:

    Listening on http://127.0.0.1:3773
    Tailscale Serve configured

  3. Open the Tailscale Serve URL from another device: https://<machine>.<tailnet>.ts.net

  4. Navigate to Settings → Connections.

  5. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.