repo/services/README.md

4.8 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 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:

    cd installer
    bun run catalog
    

    This 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 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:

"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. allproxauthelialldap) 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. For 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}"]
}

The installer turns it into:

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):

{
  "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.