- 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.
6.4 KiB
services
One folder per service. Each folder must contain a metadata.json describing the service
(including the Docker Compose definition used to deploy it). The folder may also contain any extra
files the service needs — a config file, a Dockerfile, static assets — which the installer copies
into the deploy directory.
Folder conventions
-
The folder name must equal the service
idinmetadata.json(lowercase kebab-case). -
Only folders that contain a valid
metadata.jsonare treated as services by the installer. -
After adding, editing, or removing a service, regenerate the index:
cd installer bun run catalogThis rewrites
catalog.json, which the installer uses as a one-request listing.
Extra files
A service folder can contain files beyond metadata.json — for example the authelia service ships
a configuration.yml and a users_database.yml, while the multistreaming service ships a Dockerfile,
package.json, src/, and web/ for its build. On install/update the installer copies the whole
folder (except metadata.json) into ~/.homelab/services/<id>/, preserving subdirectories.
Reference those files from compose.volumes with relative paths:
"volumes": [
"./configuration.yml:/config/configuration.yml:ro",
"./users_database.yml:/config/users_database.yml:ro"
]
Because the generated docker-compose.yml lives in the same directory, docker compose resolves
the ./... paths against it — and, for build services, the . build context is that same
directory, so the Dockerfile and source files are found automatically.
Shared networks
Services that need to talk to each other (e.g. nginx-proxy-manager → authelia → lldap) join an external
Docker network. Declare it at the top level of metadata.json and attach the service to it:
"networks": { "homelab": { "external": true } },
"compose": {
"networks": ["homelab"]
}
The installer creates the external network automatically (if it doesn't already exist) before
running docker compose up.
metadata.json reference
| Field | Required | Type | Description |
|---|---|---|---|
id |
✅ | string | Unique kebab-case id, equal to the folder name. |
name |
✅ | string | Human-readable name shown in the TUI. |
description |
✅ | string | Short description. |
version |
✅ | string | Version string for change detection on update. |
compose |
✅ | object | A Docker Compose service definition (image, ports, volumes, environment, …). The installer wraps it in a generated docker-compose.yml. |
volumes |
— | object | Optional top-level named volumes to declare. |
networks |
— | object | Optional top-level networks to declare. |
env |
— | array | Variables the installer resolves for you (see below). |
category |
— | string | Grouping shown as a hint in the TUI. |
tags |
— | string[] | Free-form tags. |
icon |
— | string | URL to an icon. |
author |
— | string | Upstream author. |
license |
— | string | License of the deployed software. |
homepage |
— | string | Project homepage URL. |
documentation |
— | string | Documentation URL. |
dependsOn |
— | string[] | Ids of services that should be installed first (informational). |
notes |
— | string | Free-form notes shown by info. |
A machine-readable JSON Schema is available at docs/metadata-schema.json.
compose (the service definition)
This object is the value you would normally put under a service key in docker-compose.yml. It must
set either image (pull a prebuilt image) or build (build from a Dockerfile shipped in the
service folder). Pull example:
{
"image": "ghcr.io/example/myapp:1.0.0",
"container_name": "myapp",
"restart": "unless-stopped",
"ports": ["8080:8080"],
"volumes": ["myapp_data:/data"],
"environment": ["TZ=${TZ}"]
}
Build example (the Dockerfile, source files, and .dockerignore live in the service folder and are
copied into the deploy directory, so the build context is .):
{
"build": { "context": ".", "dockerfile": "Dockerfile" },
"container_name": "myapp",
"restart": "unless-stopped",
"ports": ["8080:8080"],
"volumes": ["myapp_data:/data"],
"environment": ["TZ=${TZ}"]
}
The installer turns either into a docker-compose.yml service. On install it runs
docker compose build (for build services) or pulls the image on update; then docker compose up -d
brings the container up. For image-based services, pin the tag so updates are predictable — the
installer compares version to decide whether an update is available.
env (interactive variables)
Each entry describes a variable the installer should collect (and write to .env):
{
"name": "WEBPASSWORD",
"label": "Web admin password",
"description": "Password for the web UI",
"default": "change-me",
"required": true,
"secret": true,
"options": []
}
name(required) — the variable name. Reference it incomposeas${NAME}.label/description— shown when prompting.default— used when the user accepts the default or runs non-interactively.required— a missing value is an error in non-interactive mode unless adefaultis set.secret— mask input at the prompt (e.g. passwords).options— if provided, the installer offers a fixed choice list instead of free text.generate— generate a random 64-char hex secret instead of prompting (for JWT/session secrets).
Docker Compose automatically reads the .env written next to the generated compose file, so
${NAME} references resolve at docker compose up time.
rsaKeys (generated private keys)
For secrets that cannot be injected via environment variables — most notably Authelia's OIDC
signing key (identity_providers.oidc.jwks.key, which rejects $file:/$env: secret references) —
declare an RSA private key the installer generates into a file on first install:
"rsaKeys": [
{ "name": "OIDC_JWKS_KEY", "path": "oidc-jwks.pem", "bits": 2048 }
]
name(required) — human label.path(required) — file written into the service's deploy directory, referenced by a relative./path:...bind mount incompose.volumes.bits— RSA modulus size (default 2048).
The key is only created if the file is absent, so updating a service never rotates the key and invalidates existing sessions.