# homelab 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 [`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. ``` 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 │ ├── authelia/ # SSO / IdP (login portal, OIDC, forward-auth) │ │ ├── metadata.json │ │ ├── configuration.yml │ │ └── users_database.yml │ ├── lldap/ # lightweight LDAP user store │ │ └── metadata.json │ └── ... ├── installer/ # Bun + TypeScript TUI │ ├── src/ │ └── scripts/ └── docs/ └── metadata-schema.json ``` ## Identity stack (SSO) Three services work together for single sign-on: ``` browser ──▶ allprox (Caddy) ──forward_auth──▶ 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://:17170`). 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`: ```bash bun run src/index.ts install lldap authelia allprox ``` ## Quick start ```bash # 1. Install Bun: https://bun.sh # 2. Install the installer's dependencies cd installer bun install # 3. Launch the TUI bun run src/index.ts ``` The TUI lets you browse the catalog, install services, update them, uninstall them, and inspect what is currently running. Services are deployed with `docker compose` into `~/.homelab/services//` (a `docker-compose.yml` and a `.env` are generated from each `metadata.json`). > **Requirement:** Docker must be installed and the `docker` command available on your `PATH`. ## Non-interactive CLI 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 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 status ``` Useful flags: | Flag | Meaning | | --- | --- | | `--local ` | Read services from a local folder instead of GitHub (handy while developing a new service). | | `--owner/--repo/--branch` | Override the GitHub source (also available as `HOMELAB_OWNER`, `HOMELAB_REPO`, `HOMELAB_BRANCH`). | | `--env KEY=VALUE` | Provide an environment value non-interactively (repeatable). | | `--yes` | Never prompt; use defaults or provided `--env` values. | | `--dry-run` | Print what would happen (including the generated compose file) without touching Docker. | | `--force` | Re-run an update even if versions already match. | | `--verbose` | Stream `docker compose` output instead of only showing failures. | ## How the CDN works The installer treats this GitHub repository as its content delivery network: 1. It lists services from [`services/catalog.json`](services/catalog.json) (one request). If that file is missing it falls back to the GitHub `git/trees` API. 2. Each service's `metadata.json` is fetched from `https://raw.githubusercontent.com////services//metadata.json`. Pointing the installer at your own fork is just a matter of setting `--owner`/`--repo` (or the `HOMELAB_*` environment variables). For a **private** repository, export a GitHub token and the installer authenticates its API and raw requests automatically: `HOMELAB_GITHUB_TOKEN` (or `GITHUB_TOKEN` / `HOMELAB_TOKEN`). The repository must be pushed — the installer reads from GitHub, not from your local checkout. Adding a new service means adding a folder plus its `metadata.json` and regenerating the catalog: ```bash cd installer bun run catalog ``` ## Adding a service 1. Create `services//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 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. ## Service metadata at a glance `metadata.json` is the single source of truth for a service. The essential shape: ```json { "id": "allprox", "name": "allprox", "description": "Caddy reverse proxy with an SSO-ready portal", "version": "1.0.0", "category": "network", "compose": { "image": "caddy:2-alpine", "container_name": "allprox", "restart": "unless-stopped", "ports": ["80:80", "443:443"], "volumes": ["./Caddyfile:/etc/caddy/Caddyfile:ro", "allprox_data:/data"], "environment": ["PORTAL_AUTH_HASH=${PORTAL_AUTH_HASH}"] }, "volumes": { "allprox_data": {} }, "env": [ { "name": "PORTAL_AUTH_HASH", "label": "Portal admin password hash", "secret": true } ] } ``` - `compose` is a standard Docker Compose *service* definition (image, ports, volumes, environment, …). The installer wraps it in a generated `docker-compose.yml`. - `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`. See [`docs/metadata-schema.json`](docs/metadata-schema.json) for the complete, machine-readable schema. ## License This repository is a personal template. Service entries reference their upstream projects; each service's own license applies to the software it deploys.