fix: add explicit tailnet gateway bind
This commit is contained in:
@@ -72,14 +72,14 @@ describe("callGateway url resolution", () => {
|
||||
closeReason = "";
|
||||
});
|
||||
|
||||
it("uses tailnet IP when local bind is auto and tailnet is present", async () => {
|
||||
it("keeps loopback when local bind is auto even if tailnet is present", async () => {
|
||||
loadConfig.mockReturnValue({ gateway: { mode: "local", bind: "auto" } });
|
||||
resolveGatewayPort.mockReturnValue(18800);
|
||||
pickPrimaryTailnetIPv4.mockReturnValue("100.64.0.1");
|
||||
|
||||
await callGateway({ method: "health" });
|
||||
|
||||
expect(lastClientOptions?.url).toBe("ws://100.64.0.1:18800");
|
||||
expect(lastClientOptions?.url).toBe("ws://127.0.0.1:18800");
|
||||
});
|
||||
|
||||
it("falls back to loopback when local bind is auto without tailnet IP", async () => {
|
||||
@@ -92,6 +92,16 @@ describe("callGateway url resolution", () => {
|
||||
expect(lastClientOptions?.url).toBe("ws://127.0.0.1:18800");
|
||||
});
|
||||
|
||||
it("uses tailnet IP when local bind is tailnet and tailnet is present", async () => {
|
||||
loadConfig.mockReturnValue({ gateway: { mode: "local", bind: "tailnet" } });
|
||||
resolveGatewayPort.mockReturnValue(18800);
|
||||
pickPrimaryTailnetIPv4.mockReturnValue("100.64.0.1");
|
||||
|
||||
await callGateway({ method: "health" });
|
||||
|
||||
expect(lastClientOptions?.url).toBe("ws://100.64.0.1:18800");
|
||||
});
|
||||
|
||||
it("uses url override in remote mode even when remote url is missing", async () => {
|
||||
loadConfig.mockReturnValue({
|
||||
gateway: { mode: "remote", bind: "loopback", remote: {} },
|
||||
|
||||
@@ -63,7 +63,7 @@ export function buildGatewayConnectionDetails(
|
||||
const localPort = resolveGatewayPort(config);
|
||||
const tailnetIPv4 = pickPrimaryTailnetIPv4();
|
||||
const bindMode = config.gateway?.bind ?? "loopback";
|
||||
const preferTailnet = bindMode === "auto" && !!tailnetIPv4;
|
||||
const preferTailnet = bindMode === "tailnet" && !!tailnetIPv4;
|
||||
const scheme = tlsEnabled ? "wss" : "ws";
|
||||
const localUrl =
|
||||
preferTailnet && tailnetIPv4
|
||||
|
||||
@@ -33,7 +33,8 @@ export function isLocalGatewayAddress(ip: string | undefined): boolean {
|
||||
* Modes:
|
||||
* - loopback: 127.0.0.1 (rarely fails, but handled gracefully)
|
||||
* - lan: always 0.0.0.0 (no fallback)
|
||||
* - auto: Tailnet IPv4 if available, else 0.0.0.0
|
||||
* - tailnet: Tailnet IPv4 if available, else loopback
|
||||
* - auto: Loopback if available, else 0.0.0.0
|
||||
* - custom: User-specified IP, fallback to 0.0.0.0 if unavailable
|
||||
*
|
||||
* @returns The bind address to use (never null)
|
||||
@@ -50,6 +51,13 @@ export async function resolveGatewayBindHost(
|
||||
return "0.0.0.0"; // extreme fallback
|
||||
}
|
||||
|
||||
if (mode === "tailnet") {
|
||||
const tailnetIP = pickPrimaryTailnetIPv4();
|
||||
if (tailnetIP && (await canBindTo(tailnetIP))) return tailnetIP;
|
||||
if (await canBindTo("127.0.0.1")) return "127.0.0.1";
|
||||
return "0.0.0.0";
|
||||
}
|
||||
|
||||
if (mode === "lan") {
|
||||
return "0.0.0.0";
|
||||
}
|
||||
@@ -64,8 +72,7 @@ export async function resolveGatewayBindHost(
|
||||
}
|
||||
|
||||
if (mode === "auto") {
|
||||
const tailnetIP = pickPrimaryTailnetIPv4();
|
||||
if (tailnetIP && (await canBindTo(tailnetIP))) return tailnetIP;
|
||||
if (await canBindTo("127.0.0.1")) return "127.0.0.1";
|
||||
return "0.0.0.0";
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ export type GatewayServerOptions = {
|
||||
* - loopback: 127.0.0.1
|
||||
* - lan: 0.0.0.0
|
||||
* - tailnet: bind only to the Tailscale IPv4 address (100.64.0.0/10)
|
||||
* - auto: prefer tailnet, else LAN
|
||||
* - auto: prefer loopback, else LAN
|
||||
*/
|
||||
bind?: import("../config/config.js").GatewayBindMode;
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user