2026-02-12 14:58:44 +01:00
2026-02-12 12:51:31 +01:00
2026-02-12 14:58:44 +01:00
2026-02-11 20:27:53 +01:00

Felhom App Catalog

Central repository for all Felhom customer application deployments.

Architecture

felhom-app-catalog/          ← This repo (source of truth)
├── templates/               # Docker Compose templates with placeholders
│   ├── actualbudget/
│   ├── docmost/
│   ├── filebrowser/
│   ├── homebox/
│   ├── immich/
│   ├── mealie/
│   ├── paperless-ngx/
│   ├── romm/
│   ├── stirling-pdf/
│   └── vaultwarden/
├── customers/               # Per-customer configuration (YAML)
│   ├── demo-felhom.yaml
│   └── pi-customer-1.yaml
├── scripts/
│   └── render.sh            # Renders output from templates + customer configs
└── output/                  # Generated monorepo (pushed to Gitea)
    ├── README.md
    ├── demo-felhom/
    │   ├── actualbudget/docker-compose.yml
    │   ├── immich/docker-compose.yml
    │   └── ...
    └── pi-customer-1/
        ├── actualbudget/docker-compose.yml
        └── ...

The output/ directory is what gets pushed to: https://gitea.dooplex.hu/admin/customers-felhom.eu

How It Works

  1. Templates contain Docker Compose files with {{DOMAIN}} and {{HDD_PATH}} placeholders
  2. Customer configs define which apps each customer gets, their domain, HDD path, and any version overrides
  3. render.sh substitutes all placeholders and generates the output directory
  4. --push commits and pushes the output to the Gitea monorepo
  5. Portainer GitOps on each customer node pulls from the same repo, using a different compose path per stack

Placeholder Reference

Placeholder Source Example
{{DOMAIN}} domain: in customer YAML demo-felhom.eu
{{HDD_PATH}} hdd_path: in customer YAML /mnt/hdd_1

Storage Strategy

  • HDD host paths ({{HDD_PATH}}/storage/...): Large user data — photos, documents, ROMs
  • Named Docker volumes (on NVMe): Databases, app config, caches — need fast I/O
  • Templates that don't use {{HDD_PATH}} work without it (e.g. ActualBudget, Mealie)
  • If a template needs {{HDD_PATH}} but the customer config doesn't set hdd_path:, the render script refuses that app and tells you what to fix

Workflow

Render & push

./scripts/render.sh                          # Render all customers locally
./scripts/render.sh --push                   # Render + commit + push to Gitea
./scripts/render.sh --customer demo-felhom   # Render one customer only
./scripts/render.sh --dry-run                # Preview what would happen
./scripts/render.sh --debug                  # Verbose output

The default Gitea repo URL is https://gitea.dooplex.hu/admin/customers-felhom.eu.git. Override with: GITEA_REPO_URL=https://... ./scripts/render.sh --push

Adding a new app to the catalog

  1. Create templates/<appname>/docker-compose.yml using {{DOMAIN}} and optionally {{HDD_PATH}}
  2. Add the app name to relevant customer configs in customers/
  3. Run ./scripts/render.sh --push

Updating an app version

  1. Edit the image tag in templates/<appname>/docker-compose.yml
  2. Run ./scripts/render.sh --push
  3. Portainer auto-detects git changes and redeploys (if polling enabled)

Customers with version overrides keep their pinned version.

Adding a new customer

  1. Create customers/<customer-id>.yaml (copy an existing one as template)
  2. Run ./scripts/render.sh --push
  3. Set up Portainer GitOps stacks on the customer node (see below)

Portainer Stack Setup (per app)

On the customer's Portainer, for each app:

  1. Stacks → Add Stack → Repository
  2. Repository URL: https://gitea.dooplex.hu/admin/customers-felhom.eu
  3. Compose path: <customer-id>/<appname>/docker-compose.yml
    • Example: demo-felhom/immich/docker-compose.yml
  4. Add environment variables (secrets — DB passwords, API keys, etc.)
  5. Enable GitOps auto-update (optional, 5-minute polling)
  6. Deploy

Environment Variables

Secrets are never stored in Git. They live in Portainer's stack environment variables on each customer node. Each template documents required env vars in comments at the top of the compose file.

Version Pinning

In a customer YAML, you can pin specific app versions:

overrides:
  immich_version: "v2.4.1"    # Don't auto-update Immich for this customer
  auto_update: false            # Skip ALL updates for this customer

App Catalog

App DB Type RAM Pi HDD Data Subdomain
ActualBudget None (file) ~50MB budget.*
Docmost PostgreSQL + Redis ~200MB ⚠️ docs.*
FileBrowser None (file) ~30MB {{HDD_PATH}}/ files.*
Homebox None (SQLite) ~50MB inventory.*
Immich PostgreSQL + Redis ~4GB {{HDD_PATH}}/storage/immich/ photos.*
Mealie None (SQLite) ~200MB recipes.*
Paperless-ngx PostgreSQL + Redis ~500MB {{HDD_PATH}}/storage/paperless/ paperless.*
ROMM MariaDB + Redis ~300MB ⚠️ {{HDD_PATH}}/storage/romm/ arcade.*
Stirling-PDF None ~200MB pdf.*
Vaultwarden None (SQLite) ~50MB vault.*
S
Description
No description provided
Readme 282 KiB
Languages
Shell 100%