# Changelog ## 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.8` → `4.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 25566–25575). 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 25565–25575, 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.txt` → `default.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 `http` → `tcp` (`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.