fix(docker): set NODE_ENV=production in the runner stage - #6
Merged
Merged
Conversation
Upstream's Dockerfile never sets NODE_ENV, and nothing in docker/ sets it
either, so every self-hosted instance runs with it unset. Two consequences
on sign.devalok.in:
- `useSecureCookies` in packages/lib/constants/auth.ts requires
NODE_ENV === 'production', so it evaluated false: session cookies were
issued without the Secure flag and without the __Secure- name prefix,
and sameSite fell back to 'lax' instead of 'none'.
- react-router resolved its *development* bundle at runtime (visible as
react-router/dist/development/... in stack traces) -- slower, more
memory, verbose errors surfaced to clients.
Set in the runner stage only, deliberately. Setting NODE_ENV as a Railway
service variable would also apply during the build, where `npm ci` in the
installer stage would omit devDependencies and break `turbo run build`
immediately after. The runner stage already installs with
`npm ci --only=production`, so nothing there needs dev deps.
Side effect: the session cookie name changes from `sessionId` to
`__Secure-sessionId`, so existing sessions are invalidated once on deploy.
DEVALOK_FORK_NOTES.md gains a "Fork-local code changes" table and adds
docker/Dockerfile to the fork-delta capture, so the next read-tree upstream
import doesn't silently drop this line.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DYNE3dT1E7bGHk8Y8joXMm
Mudit-Lal
added a commit
that referenced
this pull request
Sep 19, 2026
Third upstream sync, v2.17.0 -> v2.18.0 (134 files). Motivation is a security fix we do not have: #3166 blocks SSRF via IPv4-mapped IPv6 webhook URLs. Also picks up #3323 (libpdf upgrade), #3309 (default unset signing transport to local, which is what this instance runs) and #3351 (react router middleware). One Prisma migration, additive and nullable: 20260818081941_add_api_token_last_used_property adds ApiToken.lastUsedAt. docker/Dockerfile was hand-merged rather than patched. Upstream #3332 moved the image to node 24 / alpine 3.23, rewrote `ENV K V` into `ENV K=V`, pinned turbo from the lockfile, switched the runner stage to `npm ci --omit=dev` and strips esbuild residue. Our fork-local `ENV NODE_ENV="production"` anchors on the two lines that rewrite touched, so re-applying the patch would have conflicted; the block was placed by hand in the runner stage instead. Without it the instance serves React Router's development bundle and useSecureCookies stays false, which is the dev-mode cookie bug fixed in #6. Imported with `git read-tree -u --reset` per DEVALOK_FORK_NOTES.md, so upstream deletions carry across: apps/remix/Dockerfile.bun and apps/remix/Dockerfile.pnpm are removed. Workflow guards re-applied to 13 files / 14 jobs; upstream added and deleted no workflows this cycle. A per-job audit leaves only the two intentionally open jobs, ci.yml/build_docker and codeql-analysis.yml/analyze. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
docker/Dockerfilenever setsNODE_ENV, and nothing else indocker/sets it either — so every self-hosted Documenso built this way runs with it unset. Two consequences observed live on sign.devalok.in:1. Session cookies were not marked
Secure.packages/lib/constants/auth.ts:68:NEXT_PUBLIC_WEBAPP_URLishttps://sign.devalok.in, so the failing half wasNODE_ENV. Result: cookies issued with noSecureflag, no__Secure-name prefix, andsameSite: 'lax'instead of'none'. Verified against the running instance:2. React Router served its development bundle. Stack traces in the deploy logs resolve to
react-router/dist/development/chunk-EPOLDU6W.mjs— slower, higher memory, and verbose internals surfaced to clients.Why the runner stage specifically
NODE_ENV=productionas a Railway service variable is the obvious move and it breaks the build. Railway injects service variables at build time too, anddocker/Dockerfile:80runsnpm ciin the installer stage — withNODE_ENV=production, npm omits devDependencies, anddocker/Dockerfile:89(turbo run build --filter=@documenso/remix...) fails immediately after.The runner stage is past every build step and already installs with
npm ci --only=production(line 118), so nothing there needs dev dependencies.Side effect
The session cookie name changes from
sessionIdto__Secure-sessionId, so existing sessions are invalidated once when this deploys. Everyone signs in again — one time.Fork hygiene
DEVALOK_FORK_NOTES.mdgains a Fork-local code changes table and addsdocker/Dockerfileto thefork-delta.patchcapture. Without that, the nextgit read-tree -u --reset upstream/mainsync would silently drop this line — which is exactly how the stale-file drift in #5 happened.Worth upstreaming to
documenso/documensosince it affects every self-hoster; until that lands, it lives here.🤖 Generated with Claude Code
https://claude.ai/code/session_01DYNE3dT1E7bGHk8Y8joXMm