@rubytech/create-maxy 1.0.676 → 1.0.677
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +77 -166
- package/dist/uninstall.js +24 -0
- package/package.json +1 -1
- package/payload/platform/plugins/docs/references/deployment.md +2 -3
- package/payload/platform/plugins/docs/references/platform.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +2 -2
- package/payload/platform/scripts/vnc.sh +34 -13
- package/payload/platform/templates/systemd/maxy-edge.service +33 -0
- package/payload/server/chunk-5YIXIF6C.js +726 -0
- package/payload/server/maxy-edge.js +422 -0
- package/payload/server/server.js +543 -1809
- package/payload/platform/templates/dotfiles/.tmux.conf +0 -1
- package/payload/platform/templates/systemd/maxy-ttyd.service +0 -25
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canAccessAdmin,
|
|
3
|
+
newCorrId,
|
|
4
|
+
sanitizeClientCorrId,
|
|
5
|
+
vncLog
|
|
6
|
+
} from "./chunk-5YIXIF6C.js";
|
|
7
|
+
|
|
8
|
+
// server/maxy-edge.ts
|
|
9
|
+
import { createServer, request as httpRequest } from "http";
|
|
10
|
+
import { createConnection as createConnection2 } from "net";
|
|
11
|
+
import { readFileSync, existsSync, watchFile } from "fs";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
|
|
15
|
+
// server/ws-proxy.ts
|
|
16
|
+
import { createConnection } from "net";
|
|
17
|
+
var WS_PATH = "/websockify";
|
|
18
|
+
var UPSTREAM_TIMEOUT_MS = 5e3;
|
|
19
|
+
var HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
20
|
+
"connection",
|
|
21
|
+
"keep-alive",
|
|
22
|
+
"proxy-authenticate",
|
|
23
|
+
"proxy-authorization",
|
|
24
|
+
"te",
|
|
25
|
+
"trailer",
|
|
26
|
+
"transfer-encoding",
|
|
27
|
+
"upgrade"
|
|
28
|
+
]);
|
|
29
|
+
function attachVncWsProxy(server2, opts) {
|
|
30
|
+
const upstreamHost = opts.upstreamHost ?? "127.0.0.1";
|
|
31
|
+
const upstreamPort = opts.upstreamPort ?? 6080;
|
|
32
|
+
server2.on("upgrade", (req, clientSocket, head) => {
|
|
33
|
+
try {
|
|
34
|
+
handleUpgrade(req, clientSocket, head, {
|
|
35
|
+
isPublicHost: opts.isPublicHost,
|
|
36
|
+
upstreamHost,
|
|
37
|
+
upstreamPort
|
|
38
|
+
});
|
|
39
|
+
} catch (err) {
|
|
40
|
+
vncLog("ws-upgrade", {
|
|
41
|
+
decision: "rejected",
|
|
42
|
+
reason: "handler-exception",
|
|
43
|
+
err: err.message
|
|
44
|
+
});
|
|
45
|
+
clientSocket.destroy();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function handleUpgrade(req, clientSocket, head, opts) {
|
|
50
|
+
const url = req.url ?? "";
|
|
51
|
+
const qsIndex = url.indexOf("?");
|
|
52
|
+
const pathname = qsIndex === -1 ? url : url.slice(0, qsIndex);
|
|
53
|
+
if (pathname !== WS_PATH) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const corrId = newCorrId();
|
|
57
|
+
const query = qsIndex === -1 ? "" : url.slice(qsIndex + 1);
|
|
58
|
+
const rawClientCorrId = parseQueryParam(query, "corrId");
|
|
59
|
+
const clientCorrId = sanitizeClientCorrId(rawClientCorrId);
|
|
60
|
+
const hostHeader = (req.headers.host ?? "").split(":")[0];
|
|
61
|
+
const originHeader = headerString(req.headers.origin);
|
|
62
|
+
const remote = req.socket.remoteAddress;
|
|
63
|
+
const xff = headerString(req.headers["x-forwarded-for"]);
|
|
64
|
+
const decision = canAccessAdmin({
|
|
65
|
+
host: hostHeader,
|
|
66
|
+
remoteAddress: remote,
|
|
67
|
+
xForwardedFor: xff,
|
|
68
|
+
cookieHeader: headerString(req.headers.cookie),
|
|
69
|
+
isPublicHost: opts.isPublicHost
|
|
70
|
+
});
|
|
71
|
+
if (!decision.allow) {
|
|
72
|
+
const status = decision.reason === "public-host" ? 404 : 401;
|
|
73
|
+
vncLog("ws-upgrade", {
|
|
74
|
+
corrId,
|
|
75
|
+
clientCorrId: clientCorrId ?? null,
|
|
76
|
+
decision: "rejected",
|
|
77
|
+
reason: decision.reason,
|
|
78
|
+
ip: remote,
|
|
79
|
+
xff: xff ?? null,
|
|
80
|
+
origin: originHeader ?? null,
|
|
81
|
+
host: hostHeader
|
|
82
|
+
});
|
|
83
|
+
writeStatusAndDestroy(clientSocket, status, decision.reason === "public-host" ? "Not Found" : "Unauthorized");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const originHost = parseOriginHost(originHeader);
|
|
87
|
+
if (!originHost) {
|
|
88
|
+
vncLog("ws-upgrade", {
|
|
89
|
+
corrId,
|
|
90
|
+
clientCorrId: clientCorrId ?? null,
|
|
91
|
+
decision: "rejected",
|
|
92
|
+
reason: "origin-missing-or-invalid",
|
|
93
|
+
origin: originHeader ?? null,
|
|
94
|
+
host: hostHeader,
|
|
95
|
+
ip: remote
|
|
96
|
+
});
|
|
97
|
+
writeStatusAndDestroy(clientSocket, 403, "Forbidden");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (originHost !== hostHeader) {
|
|
101
|
+
vncLog("ws-upgrade", {
|
|
102
|
+
corrId,
|
|
103
|
+
clientCorrId: clientCorrId ?? null,
|
|
104
|
+
decision: "rejected",
|
|
105
|
+
reason: "origin-mismatch",
|
|
106
|
+
origin_host: originHost,
|
|
107
|
+
host: hostHeader,
|
|
108
|
+
ip: remote
|
|
109
|
+
});
|
|
110
|
+
writeStatusAndDestroy(clientSocket, 403, "Forbidden");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (opts.isPublicHost(originHost)) {
|
|
114
|
+
vncLog("ws-upgrade", {
|
|
115
|
+
corrId,
|
|
116
|
+
clientCorrId: clientCorrId ?? null,
|
|
117
|
+
decision: "rejected",
|
|
118
|
+
reason: "origin-public-host",
|
|
119
|
+
origin_host: originHost,
|
|
120
|
+
host: hostHeader,
|
|
121
|
+
ip: remote
|
|
122
|
+
});
|
|
123
|
+
writeStatusAndDestroy(clientSocket, 403, "Forbidden");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
vncLog("ws-upgrade", {
|
|
127
|
+
corrId,
|
|
128
|
+
clientCorrId: clientCorrId ?? null,
|
|
129
|
+
decision: "accepted",
|
|
130
|
+
ip: remote,
|
|
131
|
+
xff: xff ?? null,
|
|
132
|
+
origin: originHeader ?? null,
|
|
133
|
+
host: hostHeader,
|
|
134
|
+
sec_ws_version: headerString(req.headers["sec-websocket-version"]) ?? null,
|
|
135
|
+
sec_ws_protocol: headerString(req.headers["sec-websocket-protocol"]) ?? null
|
|
136
|
+
});
|
|
137
|
+
const upstream = createConnection({ host: opts.upstreamHost, port: opts.upstreamPort });
|
|
138
|
+
upstream.setTimeout(UPSTREAM_TIMEOUT_MS);
|
|
139
|
+
let bytesClientToUpstream = 0;
|
|
140
|
+
let bytesUpstreamToClient = 0;
|
|
141
|
+
let closedBy = null;
|
|
142
|
+
let proxyOpened = false;
|
|
143
|
+
const finish = (side, reason) => {
|
|
144
|
+
if (closedBy) return;
|
|
145
|
+
closedBy = side;
|
|
146
|
+
if (proxyOpened) {
|
|
147
|
+
vncLog("proxy-close", {
|
|
148
|
+
corrId,
|
|
149
|
+
closedBy: side,
|
|
150
|
+
reason,
|
|
151
|
+
clientBytes: bytesClientToUpstream,
|
|
152
|
+
upstreamBytes: bytesUpstreamToClient
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
clientSocket.destroy();
|
|
156
|
+
upstream.destroy();
|
|
157
|
+
};
|
|
158
|
+
upstream.once("connect", () => {
|
|
159
|
+
upstream.setTimeout(0);
|
|
160
|
+
proxyOpened = true;
|
|
161
|
+
vncLog("proxy-open", {
|
|
162
|
+
corrId,
|
|
163
|
+
upstream: `${opts.upstreamHost}:${opts.upstreamPort}`
|
|
164
|
+
});
|
|
165
|
+
const lines = [];
|
|
166
|
+
lines.push(`${req.method ?? "GET"} ${WS_PATH} HTTP/${req.httpVersion}`);
|
|
167
|
+
lines.push(`host: ${opts.upstreamHost}:${opts.upstreamPort}`);
|
|
168
|
+
for (const [name, value] of Object.entries(req.headers)) {
|
|
169
|
+
if (name === "host") continue;
|
|
170
|
+
if (HOP_BY_HOP.has(name)) continue;
|
|
171
|
+
if (value == null) continue;
|
|
172
|
+
if (Array.isArray(value)) {
|
|
173
|
+
for (const v of value) lines.push(`${name}: ${v}`);
|
|
174
|
+
} else {
|
|
175
|
+
lines.push(`${name}: ${value}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const upgradeHeader = headerString(req.headers.upgrade);
|
|
179
|
+
const connectionHeader = headerString(req.headers.connection);
|
|
180
|
+
if (upgradeHeader) lines.push(`upgrade: ${upgradeHeader}`);
|
|
181
|
+
if (connectionHeader) lines.push(`connection: ${connectionHeader}`);
|
|
182
|
+
upstream.write(lines.join("\r\n") + "\r\n\r\n");
|
|
183
|
+
if (head && head.length > 0) upstream.write(head);
|
|
184
|
+
clientSocket.on("data", (chunk) => {
|
|
185
|
+
bytesClientToUpstream += chunk.length;
|
|
186
|
+
});
|
|
187
|
+
upstream.on("data", (chunk) => {
|
|
188
|
+
bytesUpstreamToClient += chunk.length;
|
|
189
|
+
});
|
|
190
|
+
clientSocket.pipe(upstream);
|
|
191
|
+
upstream.pipe(clientSocket);
|
|
192
|
+
clientSocket.once("close", (hadError) => {
|
|
193
|
+
finish("client", hadError ? "error" : "normal");
|
|
194
|
+
});
|
|
195
|
+
upstream.once("close", (hadError) => {
|
|
196
|
+
finish("upstream", hadError ? "error" : "normal");
|
|
197
|
+
});
|
|
198
|
+
clientSocket.once("error", (err) => {
|
|
199
|
+
vncLog("proxy-error", { corrId, side: "client", err: err.message });
|
|
200
|
+
finish("client", "error");
|
|
201
|
+
});
|
|
202
|
+
upstream.once("error", (err) => {
|
|
203
|
+
vncLog("proxy-error", { corrId, side: "upstream", err: err.message });
|
|
204
|
+
finish("upstream", "error");
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
upstream.once("timeout", () => {
|
|
208
|
+
if (proxyOpened) return;
|
|
209
|
+
vncLog("proxy-error", {
|
|
210
|
+
corrId,
|
|
211
|
+
side: "upstream-connect",
|
|
212
|
+
err: "timeout",
|
|
213
|
+
timeout_ms: UPSTREAM_TIMEOUT_MS
|
|
214
|
+
});
|
|
215
|
+
writeStatusAndDestroy(clientSocket, 504, "Gateway Timeout");
|
|
216
|
+
upstream.destroy();
|
|
217
|
+
});
|
|
218
|
+
upstream.once("error", (err) => {
|
|
219
|
+
if (proxyOpened) return;
|
|
220
|
+
vncLog("proxy-error", {
|
|
221
|
+
corrId,
|
|
222
|
+
side: "upstream-connect",
|
|
223
|
+
err: err.message
|
|
224
|
+
});
|
|
225
|
+
writeStatusAndDestroy(clientSocket, 502, "Bad Gateway");
|
|
226
|
+
upstream.destroy();
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function parseQueryParam(query, key) {
|
|
230
|
+
if (!query) return null;
|
|
231
|
+
for (const pair of query.split("&")) {
|
|
232
|
+
const eq = pair.indexOf("=");
|
|
233
|
+
const k = eq === -1 ? pair : pair.slice(0, eq);
|
|
234
|
+
if (k !== key) continue;
|
|
235
|
+
const v = eq === -1 ? "" : pair.slice(eq + 1);
|
|
236
|
+
try {
|
|
237
|
+
return decodeURIComponent(v);
|
|
238
|
+
} catch {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
function headerString(value) {
|
|
245
|
+
if (value == null) return void 0;
|
|
246
|
+
return Array.isArray(value) ? value[0] : value;
|
|
247
|
+
}
|
|
248
|
+
function parseOriginHost(origin) {
|
|
249
|
+
if (!origin) return null;
|
|
250
|
+
try {
|
|
251
|
+
return new URL(origin).hostname;
|
|
252
|
+
} catch {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function writeStatusAndDestroy(socket, status, statusText) {
|
|
257
|
+
try {
|
|
258
|
+
socket.write(
|
|
259
|
+
`HTTP/1.1 ${status} ${statusText}\r
|
|
260
|
+
Connection: close\r
|
|
261
|
+
Content-Length: 0\r
|
|
262
|
+
\r
|
|
263
|
+
`
|
|
264
|
+
);
|
|
265
|
+
} catch {
|
|
266
|
+
}
|
|
267
|
+
socket.destroy();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// server/maxy-edge.ts
|
|
271
|
+
var PLATFORM_ROOT = process.env.MAXY_PLATFORM_ROOT || "";
|
|
272
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT ? join(PLATFORM_ROOT, "config", "brand.json") : "";
|
|
273
|
+
var BRAND = { configDir: ".maxy" };
|
|
274
|
+
if (BRAND_JSON_PATH && existsSync(BRAND_JSON_PATH)) {
|
|
275
|
+
try {
|
|
276
|
+
const parsed = JSON.parse(readFileSync(BRAND_JSON_PATH, "utf-8"));
|
|
277
|
+
if (typeof parsed.configDir === "string") BRAND.configDir = parsed.configDir;
|
|
278
|
+
} catch (err) {
|
|
279
|
+
console.error(`[edge] brand.json parse error: ${err.message}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
var ALIAS_DOMAINS_PATH = join(homedir(), BRAND.configDir, "alias-domains.json");
|
|
283
|
+
function loadAliasDomains() {
|
|
284
|
+
try {
|
|
285
|
+
if (!existsSync(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
|
|
286
|
+
const parsed = JSON.parse(readFileSync(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
287
|
+
if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
|
|
288
|
+
return new Set(parsed.filter((h) => typeof h === "string"));
|
|
289
|
+
} catch {
|
|
290
|
+
return /* @__PURE__ */ new Set();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
var aliasDomains = loadAliasDomains();
|
|
294
|
+
watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
295
|
+
aliasDomains = loadAliasDomains();
|
|
296
|
+
console.log(`[edge] alias-domains reloaded (${aliasDomains.size})`);
|
|
297
|
+
});
|
|
298
|
+
function isPublicHost(host) {
|
|
299
|
+
return host.startsWith("public.") || aliasDomains.has(host);
|
|
300
|
+
}
|
|
301
|
+
var EDGE_PORT = parseInt(process.env.EDGE_PORT ?? process.env.PORT ?? "19200", 10);
|
|
302
|
+
var EDGE_HOSTNAME = process.env.EDGE_HOSTNAME ?? "0.0.0.0";
|
|
303
|
+
var UPSTREAM_HOST = process.env.MAXY_UI_HOST ?? "127.0.0.1";
|
|
304
|
+
var UPSTREAM_PORT = parseInt(process.env.MAXY_UI_PORT ?? "19199", 10);
|
|
305
|
+
var WEBSOCKIFY_HOST = process.env.WEBSOCKIFY_HOST ?? "127.0.0.1";
|
|
306
|
+
var WEBSOCKIFY_PORT = parseInt(process.env.WEBSOCKIFY_PORT ?? "6080", 10);
|
|
307
|
+
var HOP_BY_HOP2 = /* @__PURE__ */ new Set([
|
|
308
|
+
"connection",
|
|
309
|
+
"keep-alive",
|
|
310
|
+
"proxy-authenticate",
|
|
311
|
+
"proxy-authorization",
|
|
312
|
+
"te",
|
|
313
|
+
"trailer",
|
|
314
|
+
"transfer-encoding",
|
|
315
|
+
"upgrade"
|
|
316
|
+
]);
|
|
317
|
+
function forwardHttp(clientReq, clientRes) {
|
|
318
|
+
const headers = {};
|
|
319
|
+
for (const [name, value] of Object.entries(clientReq.headers)) {
|
|
320
|
+
if (value == null) continue;
|
|
321
|
+
if (HOP_BY_HOP2.has(name)) continue;
|
|
322
|
+
headers[name] = value;
|
|
323
|
+
}
|
|
324
|
+
const existingXff = headers["x-forwarded-for"];
|
|
325
|
+
const remote = clientReq.socket.remoteAddress ?? "";
|
|
326
|
+
headers["x-forwarded-for"] = existingXff ? Array.isArray(existingXff) ? [...existingXff, remote].join(", ") : `${existingXff}, ${remote}` : remote;
|
|
327
|
+
const upstream = httpRequest({
|
|
328
|
+
host: UPSTREAM_HOST,
|
|
329
|
+
port: UPSTREAM_PORT,
|
|
330
|
+
method: clientReq.method,
|
|
331
|
+
path: clientReq.url,
|
|
332
|
+
headers
|
|
333
|
+
});
|
|
334
|
+
upstream.on("response", (upstreamRes) => {
|
|
335
|
+
clientRes.writeHead(upstreamRes.statusCode ?? 502, upstreamRes.statusMessage, upstreamRes.headers);
|
|
336
|
+
upstreamRes.pipe(clientRes);
|
|
337
|
+
});
|
|
338
|
+
upstream.on("error", (err) => {
|
|
339
|
+
console.error(`[edge] upstream http error path=${clientReq.url} err=${err.message}`);
|
|
340
|
+
if (!clientRes.headersSent) {
|
|
341
|
+
clientRes.writeHead(502, { "content-type": "text/plain" });
|
|
342
|
+
clientRes.end("Bad Gateway (maxy-ui unavailable)");
|
|
343
|
+
} else {
|
|
344
|
+
clientRes.destroy();
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
clientReq.on("aborted", () => upstream.destroy());
|
|
348
|
+
clientReq.pipe(upstream);
|
|
349
|
+
}
|
|
350
|
+
function forwardUpgrade(req, clientSocket, head) {
|
|
351
|
+
const upstream = createConnection2({ host: UPSTREAM_HOST, port: UPSTREAM_PORT });
|
|
352
|
+
upstream.setTimeout(5e3);
|
|
353
|
+
upstream.once("connect", () => {
|
|
354
|
+
upstream.setTimeout(0);
|
|
355
|
+
const lines = [];
|
|
356
|
+
lines.push(`${req.method ?? "GET"} ${req.url} HTTP/${req.httpVersion}`);
|
|
357
|
+
lines.push(`host: ${UPSTREAM_HOST}:${UPSTREAM_PORT}`);
|
|
358
|
+
for (const [name, value] of Object.entries(req.headers)) {
|
|
359
|
+
if (name === "host") continue;
|
|
360
|
+
if (HOP_BY_HOP2.has(name)) continue;
|
|
361
|
+
if (value == null) continue;
|
|
362
|
+
if (Array.isArray(value)) {
|
|
363
|
+
for (const v of value) lines.push(`${name}: ${v}`);
|
|
364
|
+
} else {
|
|
365
|
+
lines.push(`${name}: ${value}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const upgradeHeader = req.headers.upgrade;
|
|
369
|
+
const connectionHeader = req.headers.connection;
|
|
370
|
+
if (typeof upgradeHeader === "string") lines.push(`upgrade: ${upgradeHeader}`);
|
|
371
|
+
if (typeof connectionHeader === "string") lines.push(`connection: ${connectionHeader}`);
|
|
372
|
+
upstream.write(lines.join("\r\n") + "\r\n\r\n");
|
|
373
|
+
if (head && head.length > 0) upstream.write(head);
|
|
374
|
+
clientSocket.pipe(upstream);
|
|
375
|
+
upstream.pipe(clientSocket);
|
|
376
|
+
});
|
|
377
|
+
const teardown = (_reason) => {
|
|
378
|
+
clientSocket.destroy();
|
|
379
|
+
upstream.destroy();
|
|
380
|
+
};
|
|
381
|
+
clientSocket.once("close", () => teardown("client-close"));
|
|
382
|
+
upstream.once("close", () => teardown("upstream-close"));
|
|
383
|
+
clientSocket.once("error", () => teardown("client-error"));
|
|
384
|
+
upstream.once("error", (err) => {
|
|
385
|
+
console.error(`[edge] upstream upgrade error path=${req.url} err=${err.message}`);
|
|
386
|
+
try {
|
|
387
|
+
clientSocket.write("HTTP/1.1 502 Bad Gateway\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
|
|
388
|
+
} catch {
|
|
389
|
+
}
|
|
390
|
+
teardown("upstream-error");
|
|
391
|
+
});
|
|
392
|
+
upstream.once("timeout", () => {
|
|
393
|
+
console.error(`[edge] upstream upgrade timeout path=${req.url}`);
|
|
394
|
+
try {
|
|
395
|
+
clientSocket.write("HTTP/1.1 504 Gateway Timeout\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
|
|
396
|
+
} catch {
|
|
397
|
+
}
|
|
398
|
+
teardown("upstream-timeout");
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
var server = createServer((req, res) => {
|
|
402
|
+
forwardHttp(req, res);
|
|
403
|
+
});
|
|
404
|
+
server.keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT ?? "61000", 10);
|
|
405
|
+
server.headersTimeout = server.keepAliveTimeout + 1e3;
|
|
406
|
+
attachVncWsProxy(server, {
|
|
407
|
+
isPublicHost,
|
|
408
|
+
upstreamHost: WEBSOCKIFY_HOST,
|
|
409
|
+
upstreamPort: WEBSOCKIFY_PORT
|
|
410
|
+
});
|
|
411
|
+
server.on("upgrade", (req, socket, head) => {
|
|
412
|
+
const url = req.url ?? "";
|
|
413
|
+
const qsIndex = url.indexOf("?");
|
|
414
|
+
const pathname = qsIndex === -1 ? url : url.slice(0, qsIndex);
|
|
415
|
+
if (pathname === "/websockify") return;
|
|
416
|
+
forwardUpgrade(req, socket, head);
|
|
417
|
+
});
|
|
418
|
+
server.listen(EDGE_PORT, EDGE_HOSTNAME, () => {
|
|
419
|
+
console.log(`[edge] listening on http://${EDGE_HOSTNAME}:${EDGE_PORT}`);
|
|
420
|
+
console.log(`[edge] /websockify \u2192 ${WEBSOCKIFY_HOST}:${WEBSOCKIFY_PORT}`);
|
|
421
|
+
console.log(`[edge] everything else \u2192 ${UPSTREAM_HOST}:${UPSTREAM_PORT}`);
|
|
422
|
+
});
|