Skip to content

Commit 54a4397

Browse files
davindicodeclaude
andcommitted
Fix tunnel: conditional temp HOME + force http2 protocol
- Only use temp HOME when ~/.cloudflared/config.yml exists (named tunnel config with catch-all 404 overrides quick tunnels) - Always use --protocol http2 (QUIC/UDP blocked on many networks) - Applied to both main tunnel and per-port tunnels Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 53ce9b3 commit 54a4397

1 file changed

Lines changed: 29 additions & 15 deletions

File tree

server/tunnel.ts

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { spawn, type ChildProcess } from "child_process";
2-
import { existsSync } from "fs";
2+
import { existsSync, mkdtempSync } from "fs";
33
import { join } from "path";
4+
import { tmpdir } from "os";
45

56
// Main OTG Code tunnel
67
let mainTunnelProcess: ChildProcess | null = null;
@@ -16,6 +17,23 @@ export function setOnPortTunnelDied(cb: (port: number) => void): void {
1617
onPortTunnelDied = cb;
1718
}
1819

20+
// Check if ~/.cloudflared/config.yml exists (named tunnel config that would override quick tunnels)
21+
function hasNamedTunnelConfig(): boolean {
22+
const home = process.env.HOME || process.env.USERPROFILE || "";
23+
if (!home) return false;
24+
return existsSync(join(home, ".cloudflared", "config.yml")) ||
25+
existsSync(join(home, ".cloudflared", "config.yaml"));
26+
}
27+
28+
// Build spawn options — use temp HOME to bypass named tunnel config if present
29+
function tunnelSpawnOptions(): { env?: Record<string, string> } {
30+
if (hasNamedTunnelConfig()) {
31+
const cfHome = mkdtempSync(join(tmpdir(), "cloudflared-"));
32+
return { env: { ...process.env, HOME: cfHome } as Record<string, string> };
33+
}
34+
return {};
35+
}
36+
1937
function findCloudflared(): string {
2038
if (process.env.CLOUDFLARED_BIN && existsSync(process.env.CLOUDFLARED_BIN)) {
2139
return process.env.CLOUDFLARED_BIN;
@@ -34,13 +52,11 @@ export async function startTunnel(port: number): Promise<string | null> {
3452
const cfBin = findCloudflared();
3553

3654
try {
37-
mainTunnelProcess = spawn(
38-
cfBin,
39-
["tunnel", "--no-autoupdate", "--url", `http://localhost:${port}`],
40-
{
41-
stdio: ["ignore", "pipe", "pipe"],
42-
}
43-
);
55+
const args = ["tunnel", "--no-autoupdate", "--protocol", "http2", "--url", `http://localhost:${port}`];
56+
mainTunnelProcess = spawn(cfBin, args, {
57+
...tunnelSpawnOptions(),
58+
stdio: ["ignore", "pipe", "pipe"],
59+
});
4460
} catch {
4561
console.log(" cloudflared not found, skipping tunnel");
4662
resolve(null);
@@ -88,13 +104,11 @@ export function startPortTunnel(port: number): Promise<string | null> {
88104

89105
let proc: ChildProcess;
90106
try {
91-
proc = spawn(
92-
cfBin,
93-
["tunnel", "--no-autoupdate", "--url", `http://localhost:${port}`],
94-
{
95-
stdio: ["ignore", "pipe", "pipe"],
96-
}
97-
);
107+
const args = ["tunnel", "--no-autoupdate", "--protocol", "http2", "--url", `http://localhost:${port}`];
108+
proc = spawn(cfBin, args, {
109+
...tunnelSpawnOptions(),
110+
stdio: ["ignore", "pipe", "pipe"],
111+
});
98112
} catch {
99113
resolve(null);
100114
return;

0 commit comments

Comments
 (0)