// --------------------------------------------------------------------------- // Transparent HTTP relay for GitLab. // Runs in the netbird container's network namespace (network_mode: service) // so requests to the upstream flow over the VPN tunnel (wt0). // The dashboard's updater points GITLAB_URL at this relay. // --------------------------------------------------------------------------- const http = require("http"); const https = require("https"); const { URL } = require("url"); const PORT = parseInt(process.env.RELAY_PORT || "8080", 10); const UPSTREAM = process.env.UPSTREAM || "https://gitlab.ixsol.wien"; const upstreamBase = new URL(UPSTREAM); const client = upstreamBase.protocol === "https:" ? https : http; // Hop-by-hop / host-specific headers that must not be forwarded. const STRIP_HEADERS = new Set([ "host", "connection", "keep-alive", "transfer-encoding", "upgrade", "accept-encoding", ]); const server = http.createServer((req, res) => { if (req.method === "GET" && (req.url === "/health" || req.url === "/healthz")) { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ ok: true, upstream: UPSTREAM })); return; } const target = new URL(req.url, UPSTREAM); const headers = { ...req.headers }; for (const h of Object.keys(headers)) { if (STRIP_HEADERS.has(h.toLowerCase())) delete headers[h]; } const upstreamReq = client.request( target, { method: req.method, headers, timeout: 20000 }, (upstreamRes) => { res.writeHead(upstreamRes.statusCode || 502, upstreamRes.headers); upstreamRes.pipe(res); } ); upstreamReq.on("timeout", () => upstreamReq.destroy(new Error("Upstream timeout"))); upstreamReq.on("error", (err) => { if (res.headersSent) { res.end(); return; } res.writeHead(502, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: `GitLab relay: ${err.message}` })); }); req.pipe(upstreamReq); }); server.listen(PORT, "0.0.0.0", () => { console.log(`GitLab relay listening on 0.0.0.0:${PORT} -> ${UPSTREAM}`); });