All Docker Compose files + encrypted .env files
Find a file
2026-05-31 02:58:47 +00:00
bookstack feat: add SOPS-encrypted bookstack secrets backup 2026-04-25 21:04:44 -04:00
dashy chore(deps): update lissy93/dashy docker tag to v4.2.0 2026-05-29 21:00:30 +00:00
dispatcharr feat: add Dispatcharr IPTV manager stack (LXC 113) 2026-04-29 21:30:33 -04:00
freshrss chore(deps): update freshrss/freshrss docker tag to v1.29.1 2026-05-20 19:00:28 +00:00
frigate fix: increase frigate shm_size to 256mb (was hitting 140mb minimum warning) 2026-05-14 21:23:46 -04:00
homeassistant feat(homeassistant): upgrade from 2023.12.4 to 2026.4.4 2026-05-05 10:23:04 -04:00
komodo fix: mount docker cli-plugins into periphery container 2026-05-22 22:31:27 -04:00
mosquitto feat: add mosquitto MQTT broker 2026-05-12 21:48:10 -04:00
pinchflat fix: revert pinchflat to v2025.6.6 (v2025.9.26 tag not published to GHCR) 2026-04-24 23:13:26 -04:00
renovate chore(deps): update renovate/renovate docker tag to v43.205.2 2026-05-31 00:00:31 +00:00
tandoor chore(deps): update nginx docker tag to v1.31.1 2026-05-22 21:00:45 +00:00
wyze-bridge chore: trigger webhook test 2026-05-14 18:39:37 -04:00
.gitignore security: gitignore SSH key files in repo root 2026-04-25 22:24:38 -04:00
.pre-commit-config.yaml Pin all image tags to explicit versions for Renovate tracking 2026-04-19 22:43:52 -04:00
.sops.yaml add sops yaml, step 2.3 2026-04-10 22:59:42 -04:00
.yamllint.yaml Pin all image tags to explicit versions for Renovate tracking 2026-04-19 22:43:52 -04:00
README.md feat: add Dispatcharr IPTV manager stack (LXC 113) 2026-04-29 21:30:33 -04:00
renovate.json Add renovate.json 2026-04-20 15:59:00 +00:00

homelab-docker

Source of truth for all Docker stacks running on Nexus. Compose files live here with pinned image tags. Renovate opens PRs when newer images are available. Merging a PR to main triggers Komodo to redeploy the affected stacks automatically. SOPS-encrypted .env.enc files serve as disaster-recovery backups for secrets that can't go into git in plaintext.

Pipeline Overview

Atlas (dev machine)  ──push PR──▶  Forgejo (192.168.1.240:3000)
                                         │
                              Renovate opens PRs
                              (cron, top of every hour)
                                         │
                              you review and merge
                                         │
                              webhook fires to Komodo
                              (192.168.1.226:9120)
                                         │
                                ┌────────▼────────┐
                                │  Stage 1         │
                                │  git pull repo   │
                                └────────┬─────────┘
                                         │
                                ┌────────▼────────────────────────┐
                                │  Stage 2 (parallel)              │
                                │  Deploy Stack: dashy             │
                                │  Deploy Stack: bookstack         │
                                │  Deploy Stack: tandoor           │
                                │  Deploy Stack: homeassistant     │
                                │  Deploy Stack: pinchflat         │
                                └──────────────────────────────────┘
                                         │
                                docker compose up -d
                                (only restarts containers
                                 whose config actually changed)

Managed Services

Service Image Port Notes
dashy lissy93/dashy:4.0.0 4000 Dashboard — conf.yml tracked in this repo
bookstack linuxserver/bookstack:v22.03.1-ls11 6875 Wiki — .env gitignored, .env.enc in git
bookstack_db linuxserver/mariadb:10.5.15-r0-ls54 Shared .env with bookstack
tandoor vabene1111/recipes:2.6.9 8900 Recipes — .env gitignored, no .env.enc yet (#40)
homeassistant home-assistant:2023.12.4 8123* *network_mode: host — no port mapping in compose
pinchflat pinchflat:v2025.6.6 8945 YouTube downloader
renovate renovate/renovate:43.140.0 Cron-only; config is server-side, not in this repo
komodo komodo-core:2.1.2 9120 Orchestrator — update via SSH only, never via itself
dispatcharr ghcr.io/dispatcharr/dispatcharr:latest 9191 IPTV/EPG manager — runs on PVE LXC 113 (192.168.1.254), NOT Nexus. No semver tags yet — manual update checks required

The Happy Path — How a Normal Update Works

  1. Renovate scans — at the top of every hour, Renovate runs as a one-shot container (docker compose run --rm renovate), scans all compose files, and opens a PR in Forgejo if a newer image tag is available. Log: /mnt/server/containers/renovate/renovate.log
  2. Review the PR — check the image changelog. PRs with major version bumps automatically get a needs-manual-review label. No PRs auto-merge — all require manual approval.
  3. Merge to main — Forgejo fires a webhook to Komodo on port 9120
  4. Komodo Stage 1git pull fetches the latest compose files from Forgejo
  5. Komodo Stage 2 — five Deploy Stack actions run in parallel, each calling docker compose up -d for its stack
  6. Docker only restarts what changed — if only pinchflat's image tag changed, only that container restarts. Everything else is untouched.
  7. Verify — Komodo UI → Procedures → run history. The procedure should complete in several seconds. A run that completes in ~1ms means something is wrong (see Troubleshooting).

Images do not auto-update. Komodo does not pull new images on its own. A container only gets a new image when the tag in its compose file changes and a deployment runs. This keeps versions pinned and auditable via git history.

Secrets & SOPS Encryption

During normal operation, SOPS is not involved. Runtime .env files live only on Nexus at /home/matt/repos/homelab-docker/<service>/.env, are gitignored (**/.env), and are read directly by docker compose up -d. Komodo deploys without touching SOPS.

.env.enc files are disaster recovery only. If Nexus needs to be rebuilt from scratch, the plaintext .env files would be gone. .env.enc files are SOPS-encrypted versions committed to git so secrets can be recovered. Currently only bookstack/.env.enc exists — tandoor still needs this (issue #40).

Two age key holders — either can encrypt or decrypt:

  • Nexus: ~/.config/sops/age/keys.txt
  • Atlas: %APPDATA%\sops\age\keys.txt

Public keys are in .sops.yaml. The regex \.env(\.enc)?$ covers both .env and .env.enc files automatically.

Decrypt a backup:

sops -d --input-type dotenv --output-type dotenv bookstack/.env.enc > bookstack/.env

Never commit a plaintext .env. The .gitignore blocks **/.env and komodo/compose.env.

What Komodo Does and Doesn't Manage

Component Managed? Why
dashy, bookstack, tandoor, homeassistant, pinchflat Yes Deployed on every push to main
renovate No Cron-only; including it would trigger an unwanted scan on every push
komodo itself Never It would kill itself mid-deploy — update via SSH instead (see Known Gotchas)
dispatcharr Yes Deployed via Periphery agent on LXC 113 (192.168.1.254)

Renovate Configuration

Renovate's actual config lives server-side only at /mnt/server/containers/renovate/config.js — it contains an unencrypted Forgejo API token and is intentionally not in git. The renovate.json in this repo root is a schema reference pointer only; it contains no actual settings.

Key behaviors:

  • All PRs require manual approvalautomerge: false for all update types
  • Major version bumps — automatically labeled needs-manual-review, lower queue priority
  • Max 5 open PRs at once (prConcurrentLimit: 5)

Treat these PRs with extra caution before merging:

  • Any PR labeled needs-manual-review
  • Bookstack, Tandoor, or Home Assistant (stateful data — back up before merging)
  • Postgres or MariaDB major versions (require manual migration steps)
  • Home Assistant (breaking changes in nearly every major release)

Troubleshooting

Komodo procedure completes in ~1ms and deployed nothing

The procedure is misconfigured. Stage 2 must have 5 explicit Deploy Stack actions. If it instead has "Batch Deploy Stack If Changed," that action will always skip — stacks have no linked repo hash to compare against. Fix: Komodo UI → Procedures → edit Stage 2 → replace with 5 individual Deploy Stack actions (dashy, bookstack, tandoor, homeassistant, pinchflat).

Pull Repo stage fails — "fatal: not a git repository (or any parent up to mount point /home/matt/repos)"

Git is silently skipping .git because the repo is owned by matt but Periphery runs as root. Root is subject to git's safe.directory check; if the configured path doesn't match exactly, git traverses upward, hits the Docker bind-mount boundary at /home/matt/repos, and reports the misleading "not a git repository" error.

Check the gitconfig mounted into Periphery (komodo/.gitconfig, which becomes /root/.gitconfig in the container). It must contain at minimum:

[safe]
    directory = /home/matt/repos/homelab-docker
    directory = *

The directory = * wildcard is the safe option: Periphery runs as root and owns the host system anyway, so this doesn't weaken security. Without it, a git version mismatch or path normalization difference can silently break pulls even when the specific path entry is present.

After editing the file, the change is live immediately (the file is bind-mounted read-write into the container — no restart needed). Trigger a test pull to confirm: Komodo UI → Repos → homelab-docker → Pull.

Webhook fires but Pull Repo succeeds while stacks don't update

Check that git pull actually fetched the expected commit. In the Komodo run history for the procedure, expand Stage 1 (Pull Repo) and look at the "Latest Commit" stage output. If the commit hash doesn't match the HEAD on Forgejo, the pull ran but something (network, authentication) prevented it from reaching the remote.

Also verify that the Stack run_directory settings point to /home/matt/repos/homelab-docker/<service>. If they point elsewhere, the compose file Komodo uses won't reflect the git pull.

Komodo API — correct format for scripted operations

The Komodo REST API is served directly at the root (no /api prefix). Authentication requires both x-api-key and x-api-secret headers (not just the key). Example:

# Trigger Pull Repo manually
curl -s -X POST "http://192.168.1.226:9120/execute/PullRepo" \
  -H "x-api-key: <key>" \
  -H "x-api-secret: <secret>" \
  -H "Content-Type: application/json" \
  -d '{"repo":"homelab-docker"}'

# Trigger the full deploy procedure
curl -s -X POST "http://192.168.1.226:9120/execute/RunProcedure" \
  -H "x-api-key: <key>" \
  -H "x-api-secret: <secret>" \
  -H "Content-Type: application/json" \
  -d '{"procedure":"<procedure-id>"}'

# API docs (full OpenAPI spec)
curl http://192.168.1.226:9120/docs

API keys are created in the Komodo UI under your user profile → API Keys. Each key generates both a key (starts with K_) and a secret (starts with S_) — save both immediately, the secret is not shown again.

Webhook didn't fire after a merge

  1. Check Forgejo webhook delivery log: repo → Settings → Webhooks → recent deliveries
  2. Confirm Komodo is reachable: curl http://192.168.1.226:9120
  3. Manual deploy: ssh matt@192.168.1.226 'cd /home/matt/repos/homelab-docker/<service> && docker compose up -d'

Container running the wrong image tag

# Check what's actually running
ssh matt@192.168.1.226 'docker ps --format "table {{.Image}}\t{{.Names}}"'

# Force redeploy a specific stack
ssh matt@192.168.1.226 'cd /home/matt/repos/homelab-docker/<service> && docker compose up -d'

Service broken after image update — rollback

# Option 1: edit the compose file on Nexus to restore the old tag, redeploy
ssh matt@192.168.1.226
vi /home/matt/repos/homelab-docker/<service>/docker-compose.yml
docker compose -f /home/matt/repos/homelab-docker/<service>/docker-compose.yml up -d

# Option 2: revert the merge commit in Forgejo — Komodo redeploys on next push to main

.env file missing or corrupted on Nexus

ssh matt@192.168.1.226
cd /home/matt/repos/homelab-docker

# Bookstack has an encrypted backup:
sops -d --input-type dotenv --output-type dotenv bookstack/.env.enc > bookstack/.env
docker compose -f bookstack/docker-compose.yml up -d

# Tandoor does not have an encrypted backup yet — restore from PBS or recreate manually

Renovate not opening PRs

# Check the log
ssh matt@192.168.1.226 'tail -50 /mnt/server/containers/renovate/renovate.log'

# Trigger a manual run
ssh matt@192.168.1.226 'cd /home/matt/repos/homelab-docker/renovate && docker compose run --rm renovate'

Nexus rebuilt from scratch — full restore

  1. Install Docker via snap: sudo snap install docker
  2. Clone repo: git clone http://192.168.1.240:3000/matt/homelab-docker.git /home/matt/repos/homelab-docker
  3. Restore SOPS age key to ~/.config/sops/age/keys.txt
  4. Restore container data volumes from PBS into /mnt/server/containers/
  5. Restore .env files from .env.enc backups: sops -d --input-type dotenv --output-type dotenv <service>/.env.enc > <service>/.env
  6. Restore Renovate config from backup to /mnt/server/containers/renovate/config.js
  7. Restore Komodo .env from backup (no .env.enc exists yet for Komodo)
  8. Start stacks one at a time: cd /home/matt/repos/homelab-docker/<service> && docker compose up -d
  9. Start Komodo last

Backup Strategy

What Where Method
Container data (DBs, uploads, config) /mnt/server/containers/ on Nexus Proxmox Backup Server (192.168.1.223) — automated
Secrets bookstack/.env.enc in this repo SOPS-encrypted; tandoor (#40) and komodo still need this
Compose files & dashboard config This repo on Forgejo Every change tracked via PRs
Forgejo itself PBS Forgejo LXC on PVE is backed up by PBS

Before upgrading any stateful service, take a manual snapshot first:

ssh matt@192.168.1.226
tar czf /mnt/server/containers/backups/<service>-pre-upgrade-$(date +%Y%m%d).tar.gz /mnt/server/containers/<service>

Adding a New Service

  1. Create the compose file: <service>/docker-compose.yml with a pinned image tag
  2. Handle secrets: if the service needs a .env, create it on Nexus at /home/matt/repos/homelab-docker/<service>/.env (gitignore already covers it via **/.env), then create <service>/.env.enc as a backup (see Secrets & SOPS)
  3. Add to Komodo: Komodo UI → Stacks → New Stack → set run_directory to /home/matt/repos/homelab-docker/<service>
  4. Add to the Deploy procedure: Komodo UI → Procedures → edit Stage 2 → add a Deploy Stack action for the new stack
  5. Add to Dashy: edit dashy/conf.yml and add an entry in the appropriate section
  6. Open a PR with the compose file and Dashy changes — merging triggers the first automated deploy

Known Gotchas

  • docker compose not docker-compose — Docker on Nexus is installed via snap. The hyphenated form doesn't exist; always use the two-word form.
  • Home Assistant has no port mapping — it uses network_mode: host and binds directly to Nexus's network. Port 8123 is HA's internal default; it's not declared in the compose file.
  • Home Assistant is privileged: true — required for hardware device access. Don't remove it.
  • ConBee II must stay in the composedevices: - /dev/ttyACM0:/dev/ttyACM0 in the HA compose is the Zigbee USB dongle. Remove it and all Zigbee devices go offline.
  • Never deploy Komodo via Komodo — it would stop itself mid-deploy. To update Komodo, SSH to Nexus and run docker compose up -d in the komodo directory directly.
  • Comment-only changes don't restart containersdocker compose up -d compares the parsed config, not the raw file text. Adding a YAML comment will not trigger a restart. This is correct behavior.
  • pull_on_deploy is off — Komodo does not pull new images when deploying a stack. New images only arrive when the image tag in the compose file changes. Keep this setting off.
  • renovate.json is a placeholder — the file in the repo root is just a schema reference. Real Renovate config (Forgejo endpoint, token, PR rules) is at /mnt/server/containers/renovate/config.js on Nexus and is not in git.

Quick Reference

Thing Value
Forgejo http://192.168.1.240:3000
Komodo UI http://192.168.1.226:9120
Nexus SSH matt@192.168.1.226
Repo path on Nexus /home/matt/repos/homelab-docker
Container data /mnt/server/containers/
Renovate config (server-side) /mnt/server/containers/renovate/config.js
Renovate log /mnt/server/containers/renovate/renovate.log
SOPS age key (Nexus) ~/.config/sops/age/keys.txt
SOPS age key (Atlas) %APPDATA%\sops\age\keys.txt