Compose postgres uses POSTGRES_DB from BF_PG_DB. Dockerfile ARG
was BF_PG_DATABASE causing mismatch. PG error 3D000 db not found.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Package name changed from @betterframe/server to betterframe to
match BSB plugin path. Added nodered/package.json COPY so npm ci
can resolve the workspace dependency graph.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Base image: betterweb/service-base:9 (was :node which is v8)
- Plugin path: /home/bsb/node_modules/betterframe/ (flat pkg name)
- sec-config template: added package: betterframe to all 4 services
so BSB resolves plugins from the correct npm package
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
/mnt/bsb-plugins is declared as VOLUME in BSB base image. Build-time
COPY gets shadowed by empty anonymous volume at runtime. Use /home/bsb/
node_modules which BSB also searches and isn't a VOLUME.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BSB container mode searches /mnt/bsb-plugins/node_modules/ for
plugins. Moved built output from /home/bsb to the correct external
plugin path at /mnt/bsb-plugins/node_modules/@betterframe/server/.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BSB needs BSB_LIVE=true for production mode. Without it, warns about
non-production and tries to write sec-config.yaml (which is read-only).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BSB entrypoint at /root/entrypoint.sh runs as root and drops
privileges itself. Our USER node blocked access to entrypoint.
Removed USER root/node, use absolute COPY paths, let BSB own
the user lifecycle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sec-config.yaml is now generated at Docker build time from
sec-config.template.yaml via envsubst. Secrets come from Coolify
build args (set in UI, never in git). Template uses ${VAR:-default}
placeholders — safe to commit to public repo.
- sec-config.yaml removed from git, added to .gitignore
- sec-config.template.yaml added (public, no secrets)
- Dockerfile.server: ARGs for all config, envsubst generates config
at build time, result is chmod 444 (read-only)
- Coolify compose: removed sec-config volume mount (baked in now)
- For native installs: copy template to sec-config.yaml, fill values
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolved coolify compose conflict — took remote bind mount pattern.
All paths now use /home/bsb (BSB container workdir, not /app).
Both compose files use bind mount for sec-config.yaml.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dockerfile.server now uses betterweb/service-base:node as runtime
base instead of node:24-trixie-slim + manual bsb-plugin-cli. BSB
container handles entrypoint, user, plugin loading.
sec-config.yaml removed from Docker image — must be bind-mounted
at /app/sec-config.yaml. Both compose files updated with :ro mount.
All BF_* env vars removed from compose server service.
deploy/docker/sec-config.yaml deleted (was baked in, now mounted).
version.ts path updated for new workdir /app.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Coolify doesn't include .git in Docker build context, causing build
failure. Revert to ARG-based version stamping: compose passes
BF_SERVER_VERSION from Coolify's SOURCE_COMMIT/COOLIFY_GIT_COMMIT
env vars as a build arg, Dockerfile writes it to .bf-version. Removed
git from builder apt install (no longer needed).
Coolify pulls from GitHub and runs docker compose build — no guaranteed
env vars like SOURCE_COMMIT. Previous approach relied on ARG/ENV
passthrough that silently defaulted to "dev".
Fix: install git in the builder stage, COPY .git into context, run
git describe --tags --always to derive the version, write it to
/app/server/.bf-version. version.ts reads this file as a fallback
between env vars and the "dev" literal.
Chain: BF_SERVER_VERSION env → BF_BUILD_VERSION env → .bf-version file
→ COOLIFY_GIT_COMMIT env → SOURCE_COMMIT env → "dev".
Also: fix .gitignore for rauc-signing/ (was under wrong path).
- server Dockerfile installs wget — bookworm-slim doesn't include it
by default, so the healthcheck CMD silently failed → Coolify marked
the container unhealthy.
- nodered healthcheck swapped to /nrdp/ (always 200 when runtime up)
via wget --spider; previous /nrdp/auth/login returned non-2xx when
adminAuth disabled.
- start_period bumped to 90s for nodered's flow load on smaller hosts.
- Kiosk discovery: cloud fallback now frame-eu.betterportal.net per
the managed-fleet endpoint.
Coolify deployments don't always carry the full source tree on disk
at the bind-mount source path. Mounting a missing file lets Docker
auto-create a directory at the target, which then fails to mount over
the file the image expects.
Fix: bake config files into the images themselves:
- Dockerfile.server COPYs deploy/docker/sec-config.yaml → /app/server/.
Env vars (BF_*) still override at runtime per env-overrides.ts.
- New Dockerfile.angie wraps nginx:alpine + baked betterframe.docker.conf.
- Dockerfile.nodered COPYs nodered-settings.js to /usr/src/bf-settings.js
(outside the /data volume) and uses --settings to point at it.
Compose drops the three bind mounts; volumes are now strictly
runtime state (DB + secrets, Node-RED flows). Users who want a
different sec-config still get full control via env overrides or
Coolify's Storage UI.
- Dockerfile.server: RUN npm run build during builder stage so the
image ships pre-compiled lib/ + bsb-plugin.json. Runtime image also
installs ffmpeg (for camera snapshot endpoint).
- DisplayEditPage Show buttons + Switch dropdown now use hx-post
with hx-swap=none — no page reload, just fires the command.