From 5ff8ef55474a4e478ebadad48b76dee7466ade7d Mon Sep 17 00:00:00 2001 From: Arnaud Date: Thu, 2 Jul 2026 07:24:18 +0200 Subject: [PATCH] fix(deploy): bake NEXT_PUBLIC_* vars in at build time, not runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- Dockerfile | 11 +++++++++++ docker/DEPLOY.md | 7 +++++++ docker/compose.prod.yml | 5 +++++ 3 files changed, 23 insertions(+) diff --git a/Dockerfile b/Dockerfile index de66a52..abe4498 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 ---- diff --git a/docker/DEPLOY.md b/docker/DEPLOY.md index 546bb08..bcac781 100644 --- a/docker/DEPLOY.md +++ b/docker/DEPLOY.md @@ -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. diff --git a/docker/compose.prod.yml b/docker/compose.prod.yml index 6d8e185..d508e4b 100644 --- a/docker/compose.prod.yml +++ b/docker/compose.prod.yml @@ -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}