The portal was found crash-looping with EACCES on /app/webui_logins.
configs/webui/* are bind-mounted into the container, which reads them
through its GROUP (files 0640, group = container owner). Two paths reset
that group to the manager and never gave it back:
* init.sh setupConfigsFromRepo — `chown -R manager:manager` over the
whole configs tree on every install/redeploy (the documented local-
mode deploy), and
* the runtime config reconcile — rewriting a live config replaces the
file as the manager, so ANY release that merely adds a key to a
webui_* config would break the portal.
Neither breaks anything immediately: the running container holds its
open files, so the failure only appears at the next restart, long after
the change that caused it. That is exactly how it surfaced here — a
deploy in the evening, a dead WebUI later.
init.sh gains restoreWebuiBindAccess (prefers the root ownership helper,
inline chown fallback for the first install, no-op when the container
user does not exist yet) called right after the chown; the reconcile
calls the existing reconcileWebuiDirOwnership when it is in scope.
Verified by reproducing the break (chown -R manager over configs), then
running the fixed deploy and force-recreating the container: group is
restored to the container owner and the portal serves on 3179.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>