ci / bun-nix (pull_request) Successful in 20s
ci / docs-site (pull_request) Successful in 1m5s
ci / web (pull_request) Successful in 1m10s
ci / rust-arm64 (pull_request) Successful in 1m49s
ci / rust (pull_request) Successful in 6m23s
nix / flake (pull_request) Failing after 12m37s
Two separate things had to be wrong for this, and both were. The frame's own policy locked it out. Plugin UIs moved to their own origin so a plugin cannot act as the logged-in operator, and the plugin origin names the console as the only page allowed to frame it. It built that name from the incoming request — but Nitro hands the app a synthetic request with no TLS socket, so an HTTPS console reads back as `http:`. The header said `frame-ancestors http://host:47992` while the operator was on `https://host:47992`, and the browser refused the frame outright (ERR_BLOCKED_BY_RESPONSE). Nothing on screen said so; the reason was only in devtools. The scheme now comes from the listener's own TLS state, stamped at bind time, with x-forwarded-proto winning when something in front terminated TLS for us — the one case where the browser's scheme is not ours. And the port was shut. 47993 was added to the firewall definitions, but an already-open firewall does not pick a new port up: ufw expands an app profile into rules when you allow it and keeps those, so editing the profile on upgrade changes nothing, and firewalld needs a reload. Every upgraded Linux host kept a 47992-only rule, silently. The packages now notice on upgrade and print the one command that fixes it, without touching the running firewall. The NixOS module and the container image never learned the port at all; both now open it. Also: the console no longer mounts the frame while it is still checking whether that origin is reachable. A firewalled port drops rather than refuses, so the check hangs for the browser's whole connect timeout, and mounting meanwhile is exactly the empty panel with no explanation. The card that follows now names both causes it can be — an untrusted certificate for that port, or a closed one — because from a browser the two are indistinguishable. The rule is now a pure function with tests, since its failure mode is a well-formed header that only a browser rejects. Verified on glass against home-worker-5 (.21) and its ROM Manager plugin: the frame was refused before, renders the plugin's UI after.
36 lines
1.6 KiB
Docker
36 lines
1.6 KiB
Docker
# punktfunk management console — TanStack Start built with Bun, served by the Nitro `bun`
|
|
# preset bundle. Build context is the REPO ROOT (orval generates the API client from
|
|
# api/openapi.json, referenced as ../api/openapi.json from web/):
|
|
#
|
|
# docker build -f web/Dockerfile -t punktfunk-web .
|
|
#
|
|
# Runtime: PORT (default 47992) and PUNKTFUNK_MGMT_URL (upstream management API the Nitro
|
|
# server proxies /api to; see web/server/routes).
|
|
#
|
|
# TWO ports, not one. The console also listens on PUNKTFUNK_UI_PLUGIN_PORT (default PORT + 1 =
|
|
# 47993) and serves plugin UIs from there — a different origin, so a plugin's own code cannot act
|
|
# as the logged-in operator on the console's origin. Publish BOTH (`-p 47992:47992 -p
|
|
# 47993:47993`): the browser loads the frame from the second port directly, so a container that
|
|
# only publishes 47992 serves a console whose every plugin interface is an empty panel.
|
|
FROM oven/bun:1 AS build
|
|
WORKDIR /repo/web
|
|
|
|
# Dependency layer: lockfile only, so source edits don't re-install.
|
|
# --ignore-scripts: the root `prepare` script runs codegen, which needs sources that
|
|
# aren't copied yet — `bun run build` regenerates everything below.
|
|
COPY web/package.json web/bun.lock ./
|
|
RUN bun install --frozen-lockfile --ignore-scripts
|
|
|
|
COPY api/openapi.json /repo/api/openapi.json
|
|
COPY web/ ./
|
|
# prebuild runs orval (openapi → src/api/gen); the paraglide vite plugin compiles i18n.
|
|
RUN bun run build
|
|
|
|
FROM oven/bun:1-slim
|
|
WORKDIR /app
|
|
COPY --from=build /repo/web/.output ./.output
|
|
USER bun
|
|
ENV PORT=47992
|
|
EXPOSE 47992 47993
|
|
CMD ["bun", "run", ".output/server/index.mjs"]
|