Files
deploy-felhom-compose/controller/mnt/user-data/outputs/felhom-controller/README.md
T
2026-02-13 18:54:08 +01:00

12 KiB

felhom-controller

Central management container for Felhom home servers.

Replaces Portainer + scattered systemd scripts with a single, lightweight container that provides:

  • Hungarian-language web dashboard for customers
  • Docker Compose stack management (start/stop/update)
  • Backup orchestration (DB dumps + restic snapshots)
  • System health monitoring with Healthchecks pings
  • Git-based stack synchronization with update management
  • Self-update with automatic rollback on failure

Architecture

┌─────────────────────────────────────────────────────────────────┐
│  Customer Hardware (N100 mini PC / Raspberry Pi)                │
│                                                                 │
│  ┌──────────┐   ┌────────────────────────────────────────────┐  │
│  │ Traefik  │   │  felhom-controller                         │  │
│  │ (reverse │──▶│                                            │  │
│  │  proxy)  │   │  ┌──────────┐  ┌─────────────────────────┐│  │
│  └──────────┘   │  │ Web UI   │  │ Stack Manager           ││  │
│                 │  │ (HU dash │  │ (compose up/down/pull,  ││  │
│  ┌──────────┐   │  │  board)  │  │  git sync, update mgmt) ││  │
│  │cloudflared│   │  └──────────┘  └─────────────────────────┘│  │
│  │ (tunnel) │   │  ┌──────────┐  ┌─────────────────────────┐│  │
│  └──────────┘   │  │ Backup   │  │ Monitor & Pinger        ││  │
│                 │  │ (db dump │  │ (healthchecks pings,    ││  │
│  ┌──────────┐   │  │  restic) │  │  system metrics)        ││  │
│  │ App      │   │  └──────────┘  └─────────────────────────┘│  │
│  │ stacks   │   │  ┌──────────┐  ┌─────────────────────────┐│  │
│  │ (docker  │   │  │Scheduler │  │ REST API                ││  │
│  │ compose) │   │  │(cron-like│  │ (for UI + remote mgmt)  ││  │
│  └──────────┘   │  │  jobs)   │  └─────────────────────────┘│  │
│                 │  └──────────┘                              │  │
│                 └────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
         │ pings                              │ git pull
         ▼                                    ▼
  status.felhom.eu                   gitea.dooplex.hu
  (Healthchecks on k3s)              (stack definitions)

Module Overview

Module Path Responsibility
Config internal/config/ Load & validate controller.yaml
Stacks internal/stacks/ Docker Compose operations, catalog, container status
Backup internal/backup/ DB dumps, restic snapshots, restore
Monitor internal/monitor/ Health checks, Healthchecks pings, system metrics
Scheduler internal/scheduler/ Cron-like job runner for all periodic tasks
API internal/api/ REST API endpoints (consumed by web UI + remote mgmt)
Web internal/web/ Dashboard UI, static files, server-side templates

Stack Management

How stacks get onto the machine

  1. During initial setup, deploy-felhom-compose.sh clones the app catalog
  2. Compose files + .felhom.yml metadata land in /opt/docker/stacks/<app>/
  3. The controller periodically pulls from Git to detect changes

First deployment flow (via dashboard)

  1. Customer sees app card with "🚀 Telepítés" (Deploy) button
  2. Clicks → deploy page shows:
    • Auto-filled: DOMAIN (from controller config), read-only
    • Auto-generated: DB passwords, secret keys (shown as "✓ Generated")
    • User input: HDD path, admin password, language, etc.
    • "🎲 Generálás" button next to password fields
  3. Clicks "Telepítés" → controller:
    • Generates all secrets
    • Validates required fields (checks path exists, etc.)
    • Saves app.yaml (env vars + locked fields list)
    • Runs docker compose up -d with env vars injected
  4. Post-deploy: locked fields (DB_PASSWORD, etc.) become read-only

Update strategy

Stack updates are classified in the Git repository via markers:

Marker Behavior
No marker Optional update — shown on dashboard, customer clicks "Update"
UPDATE_REQUIRED=true Mandatory — auto-applied during next update window
UPDATE_SECURITY=true Critical — applied immediately (within minutes)

The update window is configurable per customer (default: 03:00-05:00 local time).

Protected stacks

The following stacks cannot be stopped from the customer UI:

  • traefik (reverse proxy)
  • cloudflared (tunnel)
  • felhom-controller (this container)

Backup Strategy

The controller replaces Backrest and manages backups directly:

  1. DB dumps (default 02:30): Discovers running database containers, dumps via pg_dump/mysqldump
  2. Restic snapshots (default 03:00): Backs up /opt/docker/stacks/ data + DB dumps
  3. Verification: Periodically checks snapshot integrity
  4. Pruning: Configurable retention (default: 7 daily, 4 weekly, 6 monthly)

Backup status is displayed on the dashboard and reported to Healthchecks.

Self-Update Mechanism

  1. Controller checks for new image versions periodically
  2. Before updating: creates a restic snapshot of its own config
  3. Pulls new image, recreates container
  4. Health check timeout (60s) — if new container doesn't become healthy → rollback
  5. Rollback: restores previous image tag, restarts with old config

Configuration

Controller config (infrastructure only)

Single YAML file per customer: /opt/docker/felhom-controller/controller.yaml

Contains customer identity, infrastructure secrets, backup/monitoring settings. Does not contain app-specific config (HDD paths, DB passwords, etc.).

See configs/controller.yaml.example for the full reference.

Per-app config (created during deployment)

Each deployed app gets an app.yaml in its stack directory:

# /opt/docker/stacks/paperless-ngx/app.yaml
# Auto-generated by felhom-controller — do not edit locked fields manually
deployed: true
deployed_at: "2026-02-13T14:30:00Z"
env:
  DOMAIN: "demo-felhom.eu"
  DB_PASSWORD: "a7f2b9c1e4d..."       # locked
  PAPERLESS_SECRET_KEY: "8b3e..."      # locked
  PAPERLESS_ADMIN_USER: "admin"        # editable
  HDD_PATH: "/mnt/hdd_1"              # locked
locked_fields:
  - DB_PASSWORD
  - PAPERLESS_SECRET_KEY
  - DOMAIN
  - HDD_PATH

Fields are defined in each stack's .felhom.yml metadata file. See configs/example-felhom-metadata.yml for the full format.

App assets (logos, screenshots, descriptions)

Baked into the container image at build time — no external dependencies at runtime. Assets are synced from the felhom.eu website repo before building:

make sync-assets                          # copies from ../felhom.eu/website/assets/
make sync-assets WEBSITE_ASSETS_DIR=/path # or specify custom path

Served locally at /static/assets/. Naming convention matches the website:

Asset File pattern Served at
Logo (SVG) assets/{slug}-logo.svg /static/assets/{slug}-logo.svg
Logo (PNG fallback) assets/{slug}-logo.png /static/assets/{slug}-logo.png
Screenshot assets/{slug}-screenshot-{n}.webp /static/assets/{slug}-screenshot-{n}.webp

Build & Deploy

# Build for both architectures
make build-all

# Build Docker image
make docker-build

# Push to registry
make docker-push

# Build for specific arch
make build-amd64
make build-arm64

Development

# Run locally (needs Docker socket)
go run ./cmd/controller/ --config configs/controller.yaml.example

# Run tests
go test ./...

# Lint
golangci-lint run

Repository Layout

felhom-controller/
├── cmd/controller/          # Entry point
│   └── main.go
├── internal/
│   ├── config/              # Configuration loading
│   │   └── config.go
│   ├── stacks/              # Docker Compose stack management
│   │   ├── manager.go       # Core: scan, start, stop, restart, update, logs
│   │   ├── metadata.go      # Parse .felhom.yml app metadata
│   │   └── deploy.go        # First-deploy flow: secret gen, app.yaml, compose up
│   ├── backup/              # DB dumps + restic operations (Phase 3)
│   ├── monitor/             # Health checks + metrics (Phase 2)
│   ├── scheduler/           # Periodic job runner (Phase 2)
│   ├── api/                 # REST API
│   │   └── router.go
│   └── web/                 # Dashboard UI
│       ├── server.go        # HTTP server, auth, page handlers
│       └── templates.go     # Embedded HTML templates + CSS (Hungarian)
├── configs/                 # Example config files
│   ├── controller.yaml.example
│   └── example-felhom-metadata.yml
├── docs/
│   └── BUILDING.md          # Container image build & registry guide
├── scripts/
│   └── hashpass.go          # Password hash generator
├── Dockerfile               # Multi-stage build (Go + debian-slim)
├── docker-compose.yml       # Controller's own compose definition
├── Makefile                 # Build targets (amd64, arm64, docker)
├── go.mod
└── README.md

Status & Roadmap

Phase 1 — Stack Manager + Deploy Flow (current)

  • Project skeleton & config format
  • .felhom.yml app metadata format with deploy fields
  • Per-app config persistence (app.yaml)
  • Secret generation engine (password, hex, static)
  • Stack catalog (read compose files + metadata from disk)
  • Docker Compose operations (up/down/pull/ps/logs)
  • Deploy flow with interactive field input
  • Basic web dashboard with start/stop/deploy buttons
  • REST API for stack + deploy operations
  • Simple web authentication (bcrypt sessions)
  • App logos + screenshots loaded from felhom.eu
  • Container image build pipeline (Dockerfile + Makefile)
  • First build & test on N100 hardware
  • End-to-end test: deploy an app through dashboard

Phase 2 — Monitoring & Health

  • System metrics collection (CPU, RAM, disk, temperature)
  • Healthchecks.io ping integration
  • Dashboard system health panel
  • Customer notifications (email/Telegram)

Phase 3 — Backups

  • DB dump engine (PostgreSQL, MariaDB/MySQL, SQLite)
  • Restic integration (snapshot, prune, check)
  • Backup status on dashboard
  • Manual backup trigger from UI
  • Restore workflow

Phase 4 — Git Sync & Updates

  • Periodic git pull for stack definitions
  • Update classification (optional/required/security)
  • Update window enforcement
  • Dashboard update notifications with "Update" button

Phase 5 — Self-Update & Resilience

  • Self-update check & execution
  • Pre-update config backup
  • Health-based rollback mechanism
  • Config export/import

Phase 6 — Central Management (future)

  • API authentication for remote management
  • Central dashboard on k3s querying all customer controllers
  • Fleet-wide update management