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
- During initial setup,
deploy-felhom-compose.shclones the app catalog - Compose files +
.felhom.ymlmetadata land in/opt/docker/stacks/<app>/ - The controller periodically pulls from Git to detect changes
First deployment flow (via dashboard)
- Customer sees app card with "🚀 Telepítés" (Deploy) button
- 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
- 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 -dwith env vars injected
- 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:
- DB dumps (default 02:30): Discovers running database containers, dumps via pg_dump/mysqldump
- Restic snapshots (default 03:00): Backs up
/opt/docker/stacks/data + DB dumps - Verification: Periodically checks snapshot integrity
- Pruning: Configurable retention (default: 7 daily, 4 weekly, 6 monthly)
Backup status is displayed on the dashboard and reported to Healthchecks.
Self-Update Mechanism
- Controller checks for new image versions periodically
- Before updating: creates a restic snapshot of its own config
- Pulls new image, recreates container
- Health check timeout (60s) — if new container doesn't become healthy → rollback
- 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