Docker Compose stacks for a personal homelab, deployed with Komodo. Each service lives in its own directory with a compose.yaml.
Local: Synology NAS; runs Komodo Core and the existing stacks below.debian-dev: Debian host for additional Compose stacks. Docker runs alongside the existing K3s workloads. Komodo manages its Docker workloads; K3s retains its own workloads.
| Directory | Service |
|---|---|
actual-budget |
Actual Budget, iCal export, Fintual sync |
bazarr |
Bazarr subtitles |
bentopdf |
BentoPDF |
changedetection |
ChangeDetection.io |
easy-cli-proxy |
Shared AI subscription gateway and scoped catalog sync over Tailscale |
executor |
Executor v2 apps and MCP server on Debian, accessed over Tailscale |
home-assistant |
Home Assistant |
icloudpd |
iCloud Photos sync |
immich |
Immich photo library |
infisical |
Infisical secrets manager |
jellyfin |
Jellyfin media server |
jellyplex-watched |
Jellyfin/Plex watch-state sync |
lidarr |
Lidarr music |
maintainerr |
Maintainerr |
minecraft |
Minecraft (PaperMC) |
miniflux |
Miniflux RSS reader |
ntfy |
ntfy notifications |
open-webui |
Open WebUI |
pihole |
Pi-hole DNS |
plex |
Plex |
prowlarr |
Prowlarr indexer manager |
qbittorrent |
qBittorrent |
radarr |
Radarr movies |
reactive-resume |
Reactive Resume builder |
seerr |
Seerr requests |
sitebin |
HTML reports with per-report passwords and expiry |
slashdocs |
HTML documents with comments, versions, and agent publishing |
sonarr |
Sonarr TV |
tautulli |
Tautulli Plex stats |
tdarr |
Tdarr transcoding |
tinyauth |
Private OIDC login with local accounts and optional TOTP |
trek |
Trek |
traefik |
HTTPS ingress and restricted Docker discovery |
uptime-kuma |
Uptime Kuma |
wizarr |
Wizarr invites |
Stacks are deployed through Komodo to the server selected in each stack's
configuration. Existing stacks target the Synology NAS. Host bootstrap
configuration lives under hosts/ and is applied explicitly; it is not a
Komodo stack. Compose files use environment variable placeholders; values are
injected at deploy time from Infisical (self-hosted) or
Komodo stack variables.
For local Komodo access, follow the Komodo skill. It loads credentials from Infisical and validates them with Varlock.
Renovate automerges digest, patch, and minor updates once checks pass. Major updates require review. Startup database migrations alone do not disable automerge; maintain consistent backups and follow each stack's recovery runbook.
Docker Hub images normally wait one day before updating, with package-specific
exceptions in renovate.json. GHCR does not provide release
timestamps to Renovate, so timestamp-optional lets those updates proceed
without that delay. Tinyauth and Executor publish only to GHCR and use this
behavior. Version exclusions and coordinated-image release rules are configured
separately.
Prefer upstream-maintained Docker Hub images when the same release is available
there. Pin Compose images by release tag and SHA-256 digest. If upstream has no
release tags, use a commit tag and digest, or a digest-only reference; avoid
latest, main, and master tags. Sitebin uses a commit/digest pin with manual
updates until upstream publishes versioned releases.
Secrets are organized in Infisical with one folder per stack, matching this repo's directory names (e.g. /jellyfin, /open-webui). Set values in the prod environment (or whichever environment your Komodo stacks use).
Stacks with required secrets beyond host bind-mount paths:
| Folder | Variables |
|---|---|
actual-budget |
ACTUAL_*, FINTUAL_*, GMAIL_* |
executor |
EXECUTOR_WEB_BASE_URL, BETTER_AUTH_SECRET; retain legacy v1 secrets for rollback |
icloudpd |
APPLE_USERNAME, ICLOUD_DATA_PATH, ICLOUD_SHARED_LIBRARY_ID |
immich |
DB_*, UPLOAD_LOCATION, ICLOUD_EXTERNAL_LIBRARY_PATH |
jellyfin |
JELLYFIN_PUBLISHED_SERVER_URL |
jellyplex-watched |
JELLYFIN_*, PLEX_*, sync tuning vars |
lidarr |
POSTGRES_PASSWORD |
miniflux |
POSTGRES_*, ADMIN_* |
open-webui |
WEBUI_SECRET_KEY, WEBUI_URL, CORS_ALLOW_ORIGIN |
pihole |
PIHOLE_WEB_PASSWORD |
reactive-resume |
APP_URL, POSTGRES_PASSWORD, AUTH_SECRET, optional SMTP_* |
sitebin |
SITEBIN_HOST |
slashdocs |
SLASHDOCS_APP_HOST, SLASHDOCS_RENDER_HOST, SLASHDOCS_SUBNET, POSTGRES_PASSWORD, BLOB_*, SESSION_SECRET, SLASHDOCS_OIDC_* |
tdarr |
TDARR_SERVER_IP |
tinyauth |
TINYAUTH_HOST, TINYAUTH_TRUSTED_PROXIES, TINYAUTH_USERS_BASE64, TINYAUTH_ADMIN_EMAIL, TINYAUTH_OIDC_CONFIG_BASE64 |
trek |
APP_URL |
traefik |
TRAEFIK_ACME_EMAIL, TRAEFIK_PROXY_SUBNET, TRAEFIK_PROXY_DYNAMIC_RANGE, TRAEFIK_PROXY_IP, TRAEFIK_DOCKER_API_SUBNET, TRAEFIK_NAS_HOST; optional TRAEFIK_OPENCODE_HOST, TRAEFIK_T3CODE_HOST, TRAEFIK_DOMAIN, TRAEFIK_CERT_RESOLVER |
Never commit .env files or secret values to git.
When POSTGRES_PASSWORD changes for an existing volume (Lidarr, Miniflux), update the password inside the running database before redeploying, or recreate the data volume:
# Example for Lidarr's Postgres container
docker exec -it lidarr-db psql -U lidarr -c "ALTER USER lidarr PASSWORD 'new-password';"Pi-hole picks up PIHOLE_WEB_PASSWORD on container restart.
Compose files are linted in CI with dclint:
bun install
bunx dclint . -r -c .dclintrc