From 3c994af96b4b527625f72f4912ca2c2988d4954d Mon Sep 17 00:00:00 2001 From: "Ezequiel C." Date: Fri, 11 Sep 2026 00:02:49 +0200 Subject: [PATCH] Installer: support Forgejo as catalog source; NPM dashboard bound to internal IP Co-Authored-By: Claude Code --- README.md | 11 +++++++++++ installer/src/config.ts | 9 +++++++++ installer/src/github.ts | 7 +++++-- services/nginx-proxy-manager/metadata.json | 4 ++-- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a2869ec..d8021f6 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,17 @@ installer authenticates its API and raw requests automatically: `HOMELAB_GITHUB_ `GITHUB_TOKEN` / `HOMELAB_TOKEN`). The repository must be pushed — the installer reads from GitHub, not from your local checkout. +**Forgejo (self-hosted)**: set `HOMELAB_API_BASE` and `HOMELAB_RAW_BASE` (any value other than the +GitHub defaults switches the installer to Forgejo URL/API patterns). Example — the homelab's own +Forgejo at `http://10.0.0.5:3000` (repo `Homelab/repo`, branch `master`): + +```bash +export HOMELAB_OWNER=Homelab HOMELAB_REPO=repo HOMELAB_BRANCH=master +export HOMELAB_API_BASE=http://10.0.0.5:3000/api/v1 +export HOMELAB_RAW_BASE=http://10.0.0.5:3000 +bun run src/index.ts list +``` + Adding a new service means adding a folder plus its `metadata.json` and regenerating the catalog: ```bash diff --git a/installer/src/config.ts b/installer/src/config.ts index 501c04a..205fe49 100644 --- a/installer/src/config.ts +++ b/installer/src/config.ts @@ -12,11 +12,17 @@ export interface Config { verbose: boolean; env: Record; token?: string; + apiBase: string; + rawBase: string; + forgejo: boolean; } +const GITHUB_API = "https://api.github.com"; + export function loadConfig(cli: Partial = {}): Config { const envLocal = process.env.HOMELAB_LOCAL; const localPath = cli.localPath ?? (envLocal || undefined); + const apiBase = process.env.HOMELAB_API_BASE ?? GITHUB_API; return { owner: cli.owner ?? process.env.HOMELAB_OWNER ?? "ReinadoRojo", @@ -33,6 +39,9 @@ export function loadConfig(cli: Partial = {}): Config { process.env.HOMELAB_GITHUB_TOKEN ?? process.env.GITHUB_TOKEN ?? process.env.HOMELAB_TOKEN, + apiBase, + rawBase: process.env.HOMELAB_RAW_BASE ?? "https://raw.githubusercontent.com", + forgejo: apiBase !== GITHUB_API, }; } diff --git a/installer/src/github.ts b/installer/src/github.ts index 4d17135..a784f6f 100644 --- a/installer/src/github.ts +++ b/installer/src/github.ts @@ -7,11 +7,14 @@ import { parseAndValidate } from "./metadata.ts"; const UA = "homelab-installer/1.0"; function rawUrl(cfg: Config, path: string): string { - return `https://raw.githubusercontent.com/${cfg.owner}/${cfg.repo}/${cfg.branch}/${path}`; + if (cfg.forgejo) { + return `${cfg.rawBase}/${cfg.owner}/${cfg.repo}/raw/branch/${cfg.branch}/${path}`; + } + return `${cfg.rawBase}/${cfg.owner}/${cfg.repo}/${cfg.branch}/${path}`; } function apiUrl(cfg: Config, path: string): string { - return `https://api.github.com/repos/${cfg.owner}/${cfg.repo}/${path}`; + return `${cfg.apiBase}/repos/${cfg.owner}/${cfg.repo}/${path}`; } function authHeaders(cfg: Config, scheme: "token" | "bearer"): Record { diff --git a/services/nginx-proxy-manager/metadata.json b/services/nginx-proxy-manager/metadata.json index 2b91d8e..d875931 100644 --- a/services/nginx-proxy-manager/metadata.json +++ b/services/nginx-proxy-manager/metadata.json @@ -16,7 +16,7 @@ "ports": [ "80:80", "443:443", - "81:81" + "10.0.0.5:81:81" ], "volumes": [ "npm_data:/data", @@ -31,5 +31,5 @@ "networks": { "homelab": { "external": true } }, - "notes": "Dashboard at http://:81 — first login admin@example.com / changeme (change it immediately, and restrict port 81 or apply an access list). Add Proxy Hosts like streaming.example.com -> multistreaming:8080 (enable Websockets) or auth.example.com -> authelia:9091; use the container/service name as the forward hostname since everything shares the homelab network. All proxy hosts, users, and certs persist in the npm_data and npm_letsencrypt volumes, so they survive restarts and updates. RTMP ingest is not HTTP, so it does NOT go through NPM: OBS connects directly to the multistreaming container's published port 1935 (rtmp://feed.streaming.example.com:1935/live/). SSO forward-auth for apps without OIDC: on the proxy host, add a custom location /authelia pointing to http://authelia:9091/api/authz/forward-auth with headers X-Original-URL $scheme://$http_host$request_uri, X-Forwarded-Proto $scheme, X-Forwarded-Host $http_host, X-Forwarded-Uri $request_uri, and then add `auth_request /authelia;` plus `auth_request_set $user $upstream_http_remote_user;` and `proxy_set_header Remote-User $user;` in the Advanced tab." + "notes": "Dashboard at http://10.0.0.5:81 (LAN only — port 81 is bound to the internal IP) — first login admin@example.com / changeme (change it immediately). Add Proxy Hosts like streaming.example.com -> multistreaming:8080 (enable Websockets) or auth.example.com -> authelia:9091; use the container/service name as the forward hostname since everything shares the homelab network. All proxy hosts, users, and certs persist in the npm_data and npm_letsencrypt volumes, so they survive restarts and updates. RTMP ingest is not HTTP, so it does NOT go through NPM: OBS connects directly to the multistreaming container's published port 1935 (rtmp://feed.streaming.example.com:1935/live/). SSO forward-auth for apps without OIDC: on the proxy host, add a custom location /authelia pointing to http://authelia:9091/api/authz/forward-auth with headers X-Original-URL $scheme://$http_host$request_uri, X-Forwarded-Proto $scheme, X-Forwarded-Host $http_host, X-Forwarded-Uri $request_uri, and then add `auth_request /authelia;` plus `auth_request_set $user $upstream_http_remote_user;` and `proxy_set_header Remote-User $user;` in the Advanced tab." }