Files
app-catalog-felhom.eu/CHANGELOG.md
T
admin 4581a92781 app-email: smtp_mapping for vaultwarden + mealie
Vaultwarden via STARTTLS (accepts self-signed shim cert); Mealie via plaintext
(NONE) — no accept-invalid-cert option, spike-validated mode. Compose files
reference injected ${SMTP_*}. README documents the pattern.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 08:45:23 +02:00

13 KiB
Raw Blame History

Changelog

2026-06-29 — App-email: smtp_mapping for Vaultwarden + Mealie

  • Added the smtp_mapping block to templates/vaultwarden/.felhom.yml and templates/mealie/.felhom.yml, enabling managed outbound email (app → in-controller shim → hub → Resend) for the two spike-proven apps (SPIKE-smtp-app-relay-2026-06-28). The controller injects SMTP_* at deploy/redeploy when app-email is on (global + per-app); the From address is <app>@felhom.eu. SMTP auth creds are intentionally left unset (the shim accepts no-auth on the Docker network).
    • Vaultwarden: STARTTLS (SMTP_SECURITY=starttls) + SMTP_ACCEPT_INVALID_CERTS/HOSTNAMES=true to accept the shim's self-signed cert.
    • Mealie: plaintext (SMTP_AUTH_STRATEGY=NONE) on :2525 — Mealie has no accept-invalid-cert option, so STARTTLS to a self-signed shim would fail; plaintext to the Docker-network-only shim is the spike-validated mode.
  • Both docker-compose.yml files now reference the injected ${SMTP_*} keys (with harmless defaults) so the values reach the container; empty SMTP_HOST keeps mail disabled when the toggle is off.
  • Documented the smtp_mapping pattern in README.md so further apps are easy adds.

2026-06-28 — Add SparkyFitness (v0.17.2) — nutrition/workout tracker

  • New app templates/sparkyfitness/{docker-compose.yml,.felhom.yml}: a self-hosted nutrition/calorie + workout/weight tracker (alternative to wger). Three containers — nginx frontend (SPA :80, the sole Traefik ingress, proxies /api+/uploads internally) + Node server (:3010) + dedicated postgres:15-alpine. Server + DB stay on the internal network with no Traefik labels.
  • Native email/password auth (no OIDC/Authentik — that's DooPlex-specific); subdomain sparky (deliberately ≠ wger's fitness to avoid a Host() collision). pi_compatible: false, needs_hdd: false.
  • Two DB roles: sparky (POSTGRES superuser, runs init/migrations) + sparkyapp (limited app role the server auto-creates on first boot) — separate DB_PASSWORD/APP_DB_PASSWORD. PGDATA in a pgdata subdir of the named volume. Four auto-generated, locked_after_deploy secrets; API_ENCRYPTION_KEY + BETTER_AUTH_SECRET carry data_key: true (restore recovers, never regenerates — both are 64-char hex).
  • Transcribed from the validated k3s manifest homelab-manifests/workout-system/sparkyfitness.yaml (pinned image tags, two-DB-role model, never-change crypto keys, /api/health, pg15 + PGDATA subdir).
  • Image-probe findings (build server, v0.17.2): server keeps the node -e /api/health probe (node present); frontend keeps the wget --spider probe (both wget and curl present). No probe changes needed.
  • Live-validated on guest 9201 (controller v0.87.0): synced via "Sablonok frissítése"; deployed through the real dashboard flow (Domain auto, Subdomain sparky, 4 secrets auto-gen). All 3 containers healthy; server log shows clean migrations + sparkyapp role created + RLS applied, no crash loop, no uploads EACCES; GET /api/health through the public edge returns {"status":"UP"}; login/register page serves over a valid TLS cert at https://sparky.demo-felhom.eu.

2026-06-26 — crafty-controller: image bump 4.4.8→4.10.7 + publish Java port range + connection guidance

  • Image bump crafty-4:4.4.84.10.7 (latest stable; 4.10.8/4.11.0 don't exist in the registry). 6 minor versions of fixes incl. security CVEs. Java 25 verified present in 4.10.7 (/usr/lib/jvm/java-25-openjdk-amd64, default java -version = openjdk 25.0.3; 8/11/17/21 also available) — so the latest-Minecraft (26.x, needs Java 25) blocker is resolved. Healthcheck + Traefik https-backend labels unchanged (Crafty still serves HTTPS on 8443).
  • Published the Java game-port range 25565-25575:25565-25575 (TCP, 11 ports = up to 11 Java servers; first server 25565, rest 2556625575). No network_mode: host (would break Traefik routing). Bedrock UDP 19132 intentionally out of scope.
  • App-page guidance (.felhom.yml first_steps + prerequisites): how to set the server port within 2556525575, how to connect on the LAN (manual IP:port — "scan for LAN" won't auto-list), and that internet access needs operator port-forwarding. (Static text — can't show the live LAN IP.)
  • Live-verified on guest 9201: 4.10.7 healthy; public URL 302; the guest's bridged LAN IP 192.168.0.121 reaches the real Crafty "test" server on 25565 (TCP OPEN + Minecraft SLP handshake returns JSON status); :25575 reachable, :25600 closed (negative control). In-place upgrade preserved the admin, the operator's configured MFA, and the test server.
  • Correction (earlier draft was wrong): an earlier note here claimed the upgrade "locked out the admin (TOTP)." That was a misdiagnosis — the totp_data row + recovery codes were operator-configured MFA, so the 401 on a password-only login was correct behaviour, NOT an upgrade bug. There is no upgrade regression; the bump preserves data and MFA correctly.

2026-06-26 — crafty-controller: seed a felhom-generated admin password (replaces Crafty's ugly random one)

  • crafty-controller: instead of reading Crafty's auto-generated (long, symbol-laden) random admin password, we now seed a clean felhom-generated one — same pattern as gokapi, so initial passwords are consistent across the catalog.
    • Crafty's image ships app/config_original/default.json = {"username":"admin","password":"crafty"}; "crafty" is 6 chars < Crafty's 8-char minimum, so Crafty rejected it and generated a random password.
    • New CRAFTY_PASSWORD deploy field (type: password, generate: password:24, locked after deploy — mirrors gokapi's GOKAPI_PASSWORD). The compose entrypoint overwrites the default.json template with this password before the launcher runs; on fresh install Crafty creates the admin user with it.
    • initial_credentials.file repointed default-creds.txtdefault.json (same json/username/password keys), so the controller's app-page "Kezdeti belépési adatok" card shows the seeded password — the customer sees the same value at deploy time and on the app page.
    • Catalog-only change (reuses felhom-controller v0.84.0's initial_credentials reader + the gokapi-style seed). Requires a fresh install to take effect (the seed is only read on first run).

2026-06-26 — crafty-controller: surface the auto-generated initial admin password on the app page

  • crafty-controller: Crafty writes a random admin password to /crafty/app/config/default-creds.txt at first boot (its built-in default is rejected as "too short"). Customers had to read the container logs to find it. Added an initial_credentials block (new general felhom-controller v0.84.0 mechanism): file + format: json + username_key/password_key + a note. The controller reads the file live from the container and shows username + password (masked, reveal/copy) on the app's page under "Kezdeti belépési adatok". Requires felhom-controller ≥ v0.84.0.
  • Updated first_steps to point at the app page for the initial login instead of "find it in the logs".

2026-06-26 — crafty-controller: Traefik https backend + scoped skip-verify (fixes 502)

  • crafty-controller: the healthcheck fix un-withheld the Traefik route, exposing a pre-existing 502 — Traefik proxied http://…:8443 to Crafty's HTTPS-only self-signed backend (Crafty serves no plain-HTTP panel; :8000 only redirects). Added two service labels:
    • loadbalancer.server.scheme=https — Traefik now speaks HTTPS to the backend.
    • loadbalancer.serverstransport=insecure-skip-verify@file — references the named serversTransport defined in the controller-managed Traefik dynamic config (felhom-controller v0.83.0), which skips verifying Crafty's per-container self-signed cert. Verification stays ON for every other backend (scoped Option B; no global insecureSkipVerify). The @file suffix is the cross-provider reference from the docker provider to the file-provider transport.
    • Requires felhom-controller ≥ v0.83.0 (which renders the insecure-skip-verify transport). port=8443 and the router/tls labels are unchanged.

2026-06-26 — crafty-controller healthcheck fix (curl-absent + http-vs-TLS probe)

  • crafty-controller: container was permanently unhealthy → route withheld (routeUnpublished). Two independent healthcheck root causes, both fixed in one change:
    • Docker healthcheck ran curl -fk https://localhost:8443, but the crafty-4:4.4.8 image has no curl and no wget (exec: "curl": not found, FailingStreak 150). Replaced with a dependency-free python3 TLS-socket liveness probe (/usr/bin/python3 is present): completes a TLS handshake to 127.0.0.1:8443 (unverified context mirrors the old -k; Crafty's cert is self-signed). start_period 30s → 60s for cold-boot headroom (cert gen + migrations).
    • Controller-side probe (.felhom.yml healthcheck.checks) was type: http against Crafty's TLS-only 8443 → probeHTTP sent plaintext HTTP, got a TLS record → HealthProbe.Healthy=false, which manager.go re-applies to override Docker's verdict back to unhealthy. Changed httptcp (probeTCP dial succeeds against a TLS listener). Both layers had to change together.
    • Live-validated on guest 9201 (demo-felhom): synced → recreated via the update path → Docker State.Health: healthy (ExitCode 0), health_probe.healthy: true (tcp :8443, 5ms), http-vs-TLS WARNs stopped, stable green 3+ min, Traefik now publishes the route (crafty-controller@docker).
    • Known follow-up (separate, out of this fix's scope): the public URL still returns 502 — a distinct pre-existing bug the un-withheld route exposed: Traefik proxies http://…:8443 to Crafty's HTTPS-only backend. Needs a Traefik HTTPS-backend + self-signed serversTransport (insecureSkipVerify) in the controller-generated Traefik config — tracked separately.

2026-06-23 — gokapi: index redirect + admin username display

  • gokapi: seed RedirectUrl repointed from Gokapi's GitHub default → https://${SUBDOMAIN}.${DOMAIN}/admin. Gokapi's bare root / redirects to RedirectUrl; the controller's "Megnyitás" link is always the bare subdomain root, so it was landing on Gokapi's GitHub instead of the app. Now //admin → login. Applied to the live demo (config.json edit + restart) and the seed (future deploys).
  • gokapi: added app_info.default_creds ("Felhasználó: admin · jelszó a Beállítások oldalon") so the app-info page shows the initial admin user like other apps; fixed first_steps (no more setup wizard).

2026-06-23 — gokapi reproducible headless setup (fixes public "maintenance mode")

  • gokapi: was stuck in "maintenance mode" on the public URL since first deploy — Gokapi's one-time /setup wizard was never completed, and (verified against the docs + the v1.9.6 binary) no Gokapi version supports env-var headless setup for admin credentials. Worse, the unconfigured /setup was publicly reachable = an unauthenticated admin-takeover window.
    • Fix: the compose entrypoint now seeds a config.json on first boot (admin user, this app's public URL https://${SUBDOMAIN}.${DOMAIN}/, local storage, Encryption Level 0 so it restarts without a prompt) with Password/SaltAdmin/SaltFiles cleared, then runs Gokapi's documented --deployment-password one-shot to set the felhom-generated admin password before the server starts serving. The admin account is claimed at first boot → /setup is never exposed.
    • .felhom.yml: new GOKAPI_PASSWORD deploy field (type: password, generate: password:24, shown to the customer, locked after deploy). Admin username is admin.
    • Seed is pinned to Gokapi v1.9.6 (ConfigVersion 21) — re-capture the seed if the image is bumped.
    • Live-validated on guest 9201: fresh remove+redeploy → headless auto-config, public login works, no maintenance page, admin claimed at first boot (browser-verified login).

2026-06-22 — gitea healthcheck fix (unattended test campaign)

  • gitea: healthcheck probe repointed /api/v1/version/api/healthz (docker HC + controller .felhom.yml probe), start_period 30s → 90s.
    • Surfaced during the Phase-2 deploy sweep: a fresh gitea reported unhealthy because /api/v1/version returns 404 until the install wizard / INSTALL_LOCK completes, while the container was serving fine on :3000 (/api/healthz → 200). Same class as the komga fix.

2026-06-22 — komga healthcheck fix (unattended test campaign)

  • komga: healthcheck probe repointed /api/v1/actuator/health/actuator/health.
    • Root cause: komga's Spring Boot actuator endpoint is served unauthenticated at /actuator/health (HTTP 200), while everything under the /api/v1 prefix is auth-gated — so the old probe got HTTP 401, curl -f exited 22, and the container reported unhealthy despite serving normally on :25600. Diagnosed live on guest 9201 (probe matrix: /, /actuator/health, /api/v1/oauth2/providers, /login all 200; /api/v1/actuator/health → 401).
    • The gotson/komga:1.20.0 image ships curl (verified), so the probe tool is unchanged.