Add backend data aggregator and API proxy services
- update-data.js: cron job that aggregates Google Calendar ICS feeds (today + upcoming, node-ical), Netbird reachability, Gitea/GitLab commit stats and Open WebUI models into data.json - server.js: small Node proxy behind nginx exposing /api/chat (Open WebUI completions), /api/gpu-stats and /api/ollama - gitlab-relay.js: prepared HTTP relay for GitLab over a Netbird VPN (not wired up yet; the setup key was rejected by vpn.ixsol.at) - docker-entrypoint.sh: starts updater in the background, API proxy, cron (15 min refresh) and nginx without blocking startup - nginx: proxy locations + no-cache for data.json - compose: TZ, token env wiring from .env, gpu-stats service (python + rocm-smi with device passthrough) - dockerignore: keep .env out of the build context
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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}`);
|
||||
});
|
||||
Reference in New Issue
Block a user