Switch famapp container from ghcr.io/ginnoir/famapp:latest to
registry.ginnoir.com/ginnoir/famapp:latest.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Portainer go-git resolves gitea.ginnoir.com inside Docker. Alias was on
the gitea container → port 443 refused. Moved alias to Caddy so go-git
reaches Caddy:443 (TLS ok) → proxies to gitea:3000.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Intermediate step on the way to 2026.5.2 — Authentik requires passing
through the latest 2025 release before jumping to 2026.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TB-006 forward_auth blocks machine clients with HTML/302; route /api on *arr
sites and /api plus socket.io on uptime (LAN/tailnet only) before forward_auth.
Also add Cursor interview-first rule and small Authentik/FreshRSS debug helpers.
Adds a named matcher @plane_api that matches /api/* requests carrying
X-API-Key, routing them directly to plane_api:8000 without hitting the
Authentik outpost. Browser/UI sessions still go through forward_auth.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Recyclarr to the media stack, pin database/object-store/Caddy/Vault images with Watchtower disabled, expose JDownloader at jd.ginnoir.com, and restrict minio/homarr/docs to internal_only. Mark TB-002–004 and TB-033 complete; bundle batch-3 OIDC env for FreshRSS, ownCloud, and Reactive Resume.
Media sites get Caddy forward_auth; Authentik scripts cover all proxy providers. BookStack OIDC and Plane admin routing fixes included, plus ops scripts for external auth on valhalla.
Native OAuth/OIDC for Homarr, BookStack, Gitea, and MinIO console; forward_auth with local auth disabled for code-server, uptime, and kopia; Caddy and Authentik scripts updated to match.
Homarr-labs stores state under /appdata; the old compose mapped empty paths and lost the dashboard on redeploy. TB-006 batch 1 adds Caddy forward_auth for 12 admin UIs with API and webhook bypasses.
Newer hashicorp/vault:latest mlocks more memory than docker's default
64KB memlock ulimit allows; vault crash-looped for ~5900 restarts with
'Failed to lock memory: cannot allocate memory' despite cap_add IPC_LOCK.
Deployed via apply-compose.ps1 -Portainer (mgmt plane, not a git stack).
Every service now reads stack.env via env_file with container-exact var
names — no ${VAR} parse-time interpolation, no Portainer UI env vars
(except stacks/dev, kept on UI-env interpolation as documented exception).
- media: drop PUID/PGID/TZ env lines (env_file covers); resolve ${ROOT}
- foundry: secrets via env_file; FOUNDRY_PATCH_URLS -> CONTAINER_PATCH_URLS
- monitoring: HOMARR_SECRET_ENCRYPTION_KEY -> SECRET_ENCRYPTION_KEY
- notify: FRESHRSS_USER composed in stack.env; TZ via env_file
- owncloud: container-exact OWNCLOUD_*/MYSQL_* keys; runtime $$ healthcheck
- resume/famapp: composites (DATABASE_URL etc.) written out in stack.env
- authentik: container-exact keys; image tag pinned in compose
- notes: couchdb creds via env_file
- remote: gains stack.env (no secrets; convention completeness)
- CLAUDE.md: env convention, valhalla-lab registration-only note, correct
on-host Portainer working-copy path (/config/portainer/compose/<id>)
Validated with docker compose config on valhalla for all 15 stacks.
handoff.json lists files captured at routing time, but the
extraction-cruft cleanup later removes files extracted out of a kept
archive. The Caddy file_server can only serve real files (not archive
interiors), so existence-filter the art + guide rel-paths against
library/<slug>/ before embedding/linking them — dropping phantom
entries that would 404.
handoff.py classifies completed downloads (console rom vs RPG-Maker fangame vs
patch, via bsdtar archive peek incl. RAR5), copies console roms into
Emulation/roms/<platform> for RomM, moves the full folder (rom + guides) into
the library archive, and renders note.md + handoff.json per hack for the
Obsidian publish step. Wired into the cycle; single /data mount keeps moves as
fast renames. Validated on 4 real games.
process_file now marks messages processed only after a real crawljob write, so
DRY_RUN no longer poisons the state and link-less posts get re-checked after the
host filter widens. State file reset alongside this so the arm cycle re-enqueues
all threads.
The tyrrrz/discordchatexporter image is Alpine, not Debian, and ships DCE as a
self-contained executable (no dotnet on PATH). Use apk for python3 and invoke
/opt/app/DiscordChatExporter.Cli directly.
Inert by default: empty token keeps the orchestrator idle and DRY_RUN=true
suppresses downloads. Orchestrator exports per-generation forum threads via
DiscordChatExporter, extracts download links + art, stages metadata, and writes
JDownloader crawljobs. Armed here with an alt account token and all 11 romhack
forums, still in DRY_RUN pending first-cycle validation.
scripts/deck-sgdb-art.py — runs on Deck; fetches hero, wide capsule,
and portrait/poster art from SGDB for all RomM-synced shortcuts.
scripts/deck-sgdb-art.ps1 — Windows wrapper; handles SSH ASKPASS
upload and execution.
.claude/skills/deck-sgdb/ — Claude skill documenting invocation,
file naming conventions, appid formula, and known gotchas.
External access for a trusted friend now goes through the share stack's
Tailscale serve node (roms-share.<tailnet>.ts.net), so roms.ginnoir.com
no longer needs public exposure. Add import internal_only (LAN + tailnet).