#16300: fix(tui): respect gateway bind mode in TUI connection
stale
size: XS
Cluster:
Gateway Resilience and Configuration
## Summary
Fixes #16299
The TUI's gateway connection logic was hardcoded to `ws://127.0.0.1:${localPort}` and did not respect the `gateway.bind` config setting, while the status command correctly uses `pickProbeHostForBind()` to resolve the actual bind address.
## Problem
When `gateway.bind` is set to `tailnet` or `lan`, the gateway listens only on the Tailscale IP or LAN IP respectively. However, the TUI's `resolveGatewayConnection()` function hardcodes the connection to `127.0.0.1`, causing connection failures.
## Solution
- Import `pickPrimaryTailnetIPv4` from `../infra/tailnet.js`
- Import `pickPrimaryLanIPv4` from `../gateway/net.js`
- Resolve local host based on `config.gateway.bind` mode before constructing the WebSocket URL
- Replace hardcoded `127.0.0.1` with the resolved host
The logic mirrors `pickProbeHostForBind()` used by the status command.
## Testing
Tested with:
- `gateway.bind: "tailnet"` - TUI connects to Tailscale IP
- `gateway.bind: "lan"` - TUI connects to LAN IP
- `gateway.bind: "loopback"` - TUI connects to 127.0.0.1 (default)
- `gateway.bind: "custom"` - TUI connects to custom host
## Impact
- ✅ Users can now use TUI when gateway is bound to tailnet/lan/custom
- ✅ Consistent behavior between status command and TUI
- ✅ No breaking changes - defaults to loopback (127.0.0.1)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixed TUI gateway connection to respect the `gateway.bind` config setting by resolving the bind host dynamically based on the configured mode (tailnet/lan/custom/loopback). The implementation correctly mirrors the existing `pickProbeHostForBind()` logic used by the status command, ensuring consistent behavior across different bind modes. The change replaces the hardcoded `127.0.0.1` with dynamic host resolution that supports Tailscale IPs, LAN IPs, custom hosts, and loopback, with proper fallback to loopback when IPs cannot be determined.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with no concerns
- The implementation correctly mirrors existing, well-tested logic from `pickProbeHostForBind()`, uses proper fallback strategies for all bind modes, maintains backward compatibility, and has no logical errors or security concerns
- No files require special attention
<sub>Last reviewed commit: 0f07019</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#19437: Gateway: respect custom bind host for local health/RPC target resol...
by frudas24 · 2026-02-17
82.7%
#14564: fix(gateway): crashes on startup when tailscale meets non-loopback ...
by yinghaosang · 2026-02-12
82.5%
#19026: fix(gateway): use loopback for local CLI-to-gateway connections
by Phineas1500 · 2026-02-17
81.7%
#22056: fix(gateway): use loopback for self-connections regardless of bind ...
by usedhonda · 2026-02-20
81.6%
#21772: [Bug]: Allow ws:// to Tailscale CGNAT addresses
by AIflow-Labs · 2026-02-20
81.1%
#22110: fix(tools): prefer loopback for internal tool-to-gateway RPC calls
by pierreeurope · 2026-02-20
80.4%
#21256: fix: treat ws:// to Tailscale addresses as secure when bind=tailnet
by jessewunderlich · 2026-02-19
79.7%
#22453: fix(tui): resolve and pass tlsFingerprint for secure connections [A...
by captmoss · 2026-02-21
77.4%
#7852: fix(gateway): use port from Host header for canvasHostUrl (reverse ...
by tonimelisma · 2026-02-03
75.8%
#21635: Fix status --deep showing tailscale off while tailnet is active
by graysurf · 2026-02-20
75.4%