fix(deploy): bake NEXT_PUBLIC_* vars in at build time, not runtime

NEXT_PUBLIC_VAPID_PUBLIC_KEY (and the OAuth *_ENABLED flags) are inlined
into the client bundle by next build — setting them as container env vars
at runtime does nothing, since the client JS was already built without
them. Client bundle shipped with applicationServerKey: undefined, so
pushManager.subscribe() threw and the button always failed with "Failed
to enable notifications."

Wire them as Docker build args (Dockerfile ARG/ENV before `next build`,
compose.prod.yml build.args), sourced from the same stack env vars used
at runtime so they stay in sync.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-02 07:24:18 +02:00
parent fbae04f824
commit 5ff8ef5547
3 changed files with 23 additions and 0 deletions
+11
View File
@@ -30,6 +30,17 @@ COPY . .
# link. No secrets are needed at build time — they're injected at container runtime.
RUN rm -f apps/web/.env.local && touch apps/web/.env.local
ENV NEXT_TELEMETRY_DISABLED=1
# NEXT_PUBLIC_* vars are inlined into the client bundle at build time, not read at
# container runtime — must be passed as build args (compose.prod.yml wires these
# from the same stack env vars used at runtime, so they stay in sync).
ARG NEXT_PUBLIC_VAPID_PUBLIC_KEY
ARG NEXT_PUBLIC_GITHUB_ENABLED
ARG NEXT_PUBLIC_DISCORD_ENABLED
ARG NEXT_PUBLIC_AUTHENTIK_ENABLED
ENV NEXT_PUBLIC_VAPID_PUBLIC_KEY=$NEXT_PUBLIC_VAPID_PUBLIC_KEY
ENV NEXT_PUBLIC_GITHUB_ENABLED=$NEXT_PUBLIC_GITHUB_ENABLED
ENV NEXT_PUBLIC_DISCORD_ENABLED=$NEXT_PUBLIC_DISCORD_ENABLED
ENV NEXT_PUBLIC_AUTHENTIK_ENABLED=$NEXT_PUBLIC_AUTHENTIK_ENABLED
RUN pnpm --filter web build
# ---- runtime ----
+7
View File
@@ -51,6 +51,13 @@ Every var listed here must exist in `docker/compose.prod.yml`'s `web.environment
reach the container — Portainer stack env alone isn't enough, it only fills in `${...}` refs the
compose file declares.
`NEXT_PUBLIC_*` vars (`NEXT_PUBLIC_VAPID_PUBLIC_KEY`, `NEXT_PUBLIC_GITHUB_ENABLED`,
`NEXT_PUBLIC_DISCORD_ENABLED`, `NEXT_PUBLIC_AUTHENTIK_ENABLED`) are baked into the client JS
bundle at **build time**, not read at container startup — they're wired as Docker `build.args`
in compose.prod.yml, not just `environment`. Changing one of these requires Portainer to
actually rebuild the image (redeploy with "re-pull image and rebuild"), a plain container
restart won't pick up the new value.
5. Deploy the stack. Portainer builds `web` from the repo's root `Dockerfile` (see `build:` in compose.prod.yml) — no separate image push needed.
6. Enable GitOps updates (webhook or polling) on the stack if you want redeploy-on-push.
+5
View File
@@ -65,6 +65,11 @@ services:
build:
context: ..
dockerfile: Dockerfile
args:
NEXT_PUBLIC_VAPID_PUBLIC_KEY: ${NEXT_PUBLIC_VAPID_PUBLIC_KEY}
NEXT_PUBLIC_GITHUB_ENABLED: ${NEXT_PUBLIC_GITHUB_ENABLED}
NEXT_PUBLIC_DISCORD_ENABLED: ${NEXT_PUBLIC_DISCORD_ENABLED}
NEXT_PUBLIC_AUTHENTIK_ENABLED: ${NEXT_PUBLIC_AUTHENTIK_ENABLED}
restart: always
environment:
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}