multistreaming: scenes/composition, installer build support, service updates

- multistreaming (new): RTMP ingest + multi-platform fan-out with pluggable providers (Twitch/YouTube/Kick/custom), zero-knowledge key vaults, Authelia OIDC auth, shared rooms with editor/streamer roles, single-use invites, per-account streaming grants, and scenes & composition (grid/PiP layouts, text/image overlays, per-output audio routing).
- installer: support Dockerfile build in metadata (not just image) and RSA key generation for the Authelia OIDC JWKS.
- authelia: add OIDC provider with portainer + multistreaming clients (public + PKCE).
- services: remove allprox; add nginx-proxy-manager and portainer; update lldap; regenerate catalog.
This commit is contained in:
Ezequiel C. 2026-09-02 21:18:25 +02:00
parent bb754cdd8c
commit 187379de4e
106 changed files with 21391 additions and 286 deletions

View file

@ -3,7 +3,7 @@
A common, reusable repository for running services on a personal homelab.
Every service lives in its own folder under [`services/`](services/) and is described by a
`metadata.json` file (plus any extra files the service needs, such as a `Caddyfile`). The
`metadata.json` file (plus any extra files the service needs, such as a config file). The
[`installer/`](installer/) directory contains a Bun + TypeScript
terminal UI (TUI) that reads the catalog straight from GitHub (used as the CDN) and installs or
updates services with Docker.
@ -12,16 +12,21 @@ updates services with Docker.
homelab/
├── services/ # one folder per service
│ ├── catalog.json # generated index used by the installer (CDN listing)
│ ├── allprox/ # Caddy reverse proxy + portal
│ │ ├── metadata.json
│ │ ├── Caddyfile # proxy rules (domains → local IPs)
│ │ └── portal/index.html
│ ├── nginx-proxy-manager/ # reverse proxy dashboard (NPM)
│ │ └── metadata.json
│ ├── authelia/ # SSO / IdP (login portal, OIDC, forward-auth)
│ │ ├── metadata.json
│ │ ├── configuration.yml
│ │ └── users_database.yml
│ ├── lldap/ # lightweight LDAP user store
│ │ └── metadata.json
│ ├── multistreaming/ # self-built: OBS ingest -> multi-platform re-streaming
│ │ ├── metadata.json
│ │ ├── Dockerfile
│ │ ├── src/
│ │ └── web/
│ ├── portainer/ # Docker + network manager (VLANs, static IPs)
│ │ └── metadata.json
│ └── ...
├── installer/ # Bun + TypeScript TUI
│ ├── src/
@ -32,23 +37,53 @@ homelab/
## Identity stack (SSO)
Three services work together for single sign-on:
Every web service logs in through the same IdP ([`authelia`](services/authelia)), which authenticates
users against [`lldap`](services/lldap) and sits behind [`nginx-proxy-manager`](services/nginx-proxy-manager):
```
browser ──▶ allprox (Caddy) ──forward_auth──▶ authelia ──LDAP──▶ lldap
browser ──▶ nginx-proxy-manager ──▶ authelia ──LDAP──▶ lldap
```
- [`allprox`](services/allprox) — reverse proxy; protected routes use Caddy `forward_auth` to Authelia.
- [`authelia`](services/authelia) — the SSO server (login portal, OIDC, 2FA) that authenticates users against…
- [`lldap`](services/lldap) — the lightweight LDAP directory (web UI at `http://<host>:17170`).
Two integration modes, depending on what each app supports:
They talk to each other over a shared external Docker network named `homelab`, which the installer
creates automatically. Install `lldap` first, then `authelia`, then `allprox`:
1. **OIDC (true SSO)** — the app delegates login to Authelia. [`portainer`](services/portainer) uses
this (client `portainer` is pre-registered in Authelia).
2. **Forward-auth (proxy gate)** — the app has no OIDC, so NPM asks Authelia to authorize each
request via an `auth_request` block before forwarding. Used by `multistreaming` and lldap's web UI.
| Service | SSO mode |
| --- | --- |
| Portainer | OIDC (native) |
| multistreaming panel | forward-auth (no OIDC) |
| lldap web UI | forward-auth (no OIDC) |
| Nginx Proxy Manager | its own login (no OIDC; keep port 81 restricted) |
Authelia also exposes OIDC discovery at `https://auth.example.com/.well-known/openid-configuration`
for any future OIDC-capable app. Install order: `lldap`, `authelia`, `nginx-proxy-manager`:
```bash
bun run src/index.ts install lldap authelia allprox
bun run src/index.ts install lldap authelia nginx-proxy-manager
```
## Network & DMZ topology
[`portainer`](services/portainer) is the Docker/network manager: from its dashboard you can create
**macvlan/ipvlan networks** (each mapped to a host VLAN via its parent interface) and assign each
container a **static IP**. A typical setup keeps only the reverse proxy in the DMZ and everything
else on separate VLANs:
```
internet ──▶ DMZ VLAN (e.g. 10.0.10.0/24)
└── nginx-proxy-manager (the only public entrypoint)
├─▶ services VLAN (10.0.20.0/24) ── multistreaming, …
└─▶ identity VLAN (10.0.30.0/24) ── authelia, lldap
```
To make a VLAN usable as a macvlan parent, the tagged sub-interface must first exist on the host
(e.g. `eth0.10`, configured in `/etc/network/interfaces` or netplan — outside Docker's scope).
Then create the network in Portainer and attach services to it with the IPs you want.
## Quick start
```bash
@ -74,11 +109,11 @@ The same app works as a plain CLI:
```bash
bun run src/index.ts list
bun run src/index.ts info allprox
bun run src/index.ts install allprox
bun run src/index.ts info nginx-proxy-manager
bun run src/index.ts install nginx-proxy-manager
bun run src/index.ts update # update everything installed
bun run src/index.ts update allprox # update one service
bun run src/index.ts uninstall allprox
bun run src/index.ts update nginx-proxy-manager # update one service
bun run src/index.ts uninstall nginx-proxy-manager
bun run src/index.ts status
```
@ -120,8 +155,8 @@ bun run catalog
1. Create `services/<id>/metadata.json` (the folder name **must** equal the `id`).
2. Fill in the [metadata schema](docs/metadata-schema.json) — see [`services/README.md`](services/README.md)
for a walkthrough of every field. Add any extra files the service needs (a `Caddyfile`, a
`Dockerfile`, a static `portal/`, …) alongside `metadata.json`; the installer copies them into
for a walkthrough of every field. Add any extra files the service needs (a config file, a
`Dockerfile`, …) alongside `metadata.json`; the installer copies them into
the deploy directory, so reference them with relative bind mounts in `compose.volumes`.
3. Regenerate the catalog: `cd installer && bun run catalog`.
4. Commit and push. The installer will now offer the new service.
@ -132,22 +167,21 @@ bun run catalog
```json
{
"id": "allprox",
"name": "allprox",
"description": "Caddy reverse proxy with an SSO-ready portal",
"id": "nginx-proxy-manager",
"name": "Nginx Proxy Manager",
"description": "Reverse proxy with a web dashboard",
"version": "1.0.0",
"category": "network",
"compose": {
"image": "caddy:2-alpine",
"container_name": "allprox",
"image": "jc21/nginx-proxy-manager:2.14.0",
"container_name": "nginx-proxy-manager",
"restart": "unless-stopped",
"ports": ["80:80", "443:443"],
"volumes": ["./Caddyfile:/etc/caddy/Caddyfile:ro", "allprox_data:/data"],
"environment": ["PORTAL_AUTH_HASH=${PORTAL_AUTH_HASH}"]
"ports": ["80:80", "443:443", "81:81"],
"volumes": ["npm_data:/data", "npm_letsencrypt:/etc/letsencrypt"]
},
"volumes": { "allprox_data": {} },
"volumes": { "npm_data": {}, "npm_letsencrypt": {} },
"env": [
{ "name": "PORTAL_AUTH_HASH", "label": "Portal admin password hash", "secret": true }
{ "name": "TZ", "label": "Timezone", "default": "UTC" }
]
}
```
@ -157,8 +191,9 @@ bun run catalog
- `volumes` / `networks` are optional top-level named volumes/networks to declare.
- `env` declares variables the installer should resolve for you. Use `${NAME}` in `compose` to
reference them — the installer writes the resolved values to a `.env` file next to the compose file.
- Any other files in the service folder (e.g. `Caddyfile`, `portal/index.html`) are copied into the
deploy directory, so you can mount them with relative paths (`./Caddyfile:...`) in `compose.volumes`.
- Any other files in the service folder (e.g. `configuration.yml`, `users_database.yml`) are copied
into the deploy directory, so you can mount them with relative paths (`./configuration.yml:...`) in
`compose.volumes`.
See [`docs/metadata-schema.json`](docs/metadata-schema.json) for the complete, machine-readable schema.