Add homelab installer and services (allprox, authelia, lldap)

This commit is contained in:
Ezequiel C. 2026-09-01 18:32:56 +02:00
parent 68b23f1cbe
commit bb754cdd8c
32 changed files with 2356 additions and 1 deletions

131
services/README.md Normal file
View file

@ -0,0 +1,131 @@
# 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 `Caddyfile`, a `Dockerfile`, static assets — which the installer copies
into the deploy directory.
## Folder conventions
- The folder name **must** equal the service `id` in `metadata.json` (lowercase kebab-case).
- Only folders that contain a valid `metadata.json` are treated as services by the installer.
- After adding, editing, or removing a service, regenerate the index:
```bash
cd installer
bun run catalog
```
This rewrites [`catalog.json`](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 `allprox` service ships
a `Caddyfile` and a `portal/index.html`. 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:
```json
"volumes": [
"./Caddyfile:/etc/caddy/Caddyfile:ro",
"./portal:/srv/portal:ro"
]
```
Because the generated `docker-compose.yml` lives in the same directory, `docker compose` resolves
the `./...` paths against it.
## Shared networks
Services that need to talk to each other (e.g. `allprox``authelia``lldap`) join an external
Docker network. Declare it at the top level of `metadata.json` and attach the service to it:
```json
"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`](../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`. For
example:
```json
{
"image": "ghcr.io/example/myapp:1.0.0",
"container_name": "myapp",
"restart": "unless-stopped",
"ports": ["8080:8080"],
"volumes": ["myapp_data:/data"],
"environment": ["TZ=${TZ}"]
}
```
The installer turns it into:
```yaml
services:
myapp:
image: ghcr.io/example/myapp:1.0.0
# ...
```
Pin images to a 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`):
```json
{
"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 in `compose` as `${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 a `default` is 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.