fix(deploy): ship the production environment instead of injecting it
The deployed console called its own origin instead of the platform. The BFF
route would throw "LOYALY_API_BASE is required in production — refusing to
guess the Loyaly platform host", and from the browser that reads as a broken
login form rather than as a missing variable.
The guard was right; nothing ever set the variable. `.gitignore` had a blanket
`.env*` and `.dockerignore` excluded `.env` and `.env.*`, so the image carried
no environment at all and the only copy of the production host was a comment
in `.env.example`. Injecting it by hand at the orchestrator was the single
point of failure, and it failed.
The platform host is not a secret, so it is now committed in `.env` and copied
into the runner stage. `next build` does not fold `.env` into
`.next/standalone`, which is why the COPY is explicit; server.js chdirs to
/app and Next runs loadEnvConfig there, so the file sits beside it at the
WORKDIR root. `npm run bundle` stages it the same way for a non-Docker deploy.
This pins nothing. @next/env never overwrites a variable already present in
process.env, so anything set in Dokploy still wins — verified against
@next/env directly: a bare image resolves https://mcp.loyaly.ai, an injected
LOYALY_API_BASE overrides it, and a leaked .env.local beats both.
That last case is why `.dockerignore` still excludes `.env.*`. A developer's
.env.local points at http://127.0.0.1:8088 and loads AHEAD of .env, so one
leaking into the build context would make the deployed console call localhost
with no error to read. Confirmed the context now carries `.env` and nothing
else.
AUTH_SECRET stays out of every committed file and out of the image. It signs
the session cookie and encrypts the token bundle, so a committed value is a
session-forging key in git — the thing 8b3fbab removed from the Dockerfile.
It remains a Dokploy secret, and production still refuses to sign without it.
`.env.example` is now the template for `.env.local` rather than a second copy
of the production values, so the two files cannot drift.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
.gitignore
vendored
24
.gitignore
vendored
@@ -31,13 +31,23 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
# ...except the template, which carries no secret and is the only record of
|
||||
# which variables the app needs. `.env*` was swallowing it too, so a fresh
|
||||
# clone got no guidance at all — while AUTH_SECRET and LOYALY_API_BASE are both
|
||||
# mandatory in production and the app refuses to start without them.
|
||||
!.env.example
|
||||
# env files.
|
||||
#
|
||||
# `.env*` used to be blanket-ignored, and that was the deploy bug: the image
|
||||
# shipped with no LOYALY_API_BASE at all, so every BFF call died on "required
|
||||
# in production — refusing to guess the Loyaly platform host" and the console
|
||||
# looked like a broken login form. The production host is not a secret, so it
|
||||
# now lives in a committed `.env` and ships with the build.
|
||||
#
|
||||
# What stays ignored is the per-machine and per-secret layer:
|
||||
.env.local
|
||||
.env.*.local
|
||||
#
|
||||
# What is committed:
|
||||
# .env production defaults (no secret) — loaded by the running server
|
||||
# .env.example the template, the record of which variables exist
|
||||
#
|
||||
# AUTH_SECRET belongs in neither. It is injected by Dokploy at runtime.
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
Reference in New Issue
Block a user