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>
58 lines
1.5 KiB
Plaintext
58 lines
1.5 KiB
Plaintext
# Docker build context excludes.
|
|
#
|
|
# WITHOUT this file, the `COPY . .` in the builder stage ships the host's
|
|
# .next/ (2.1 GB, almost all of it the Turbopack dev cache) and node_modules/
|
|
# (639 MB, with darwin-arm64 sharp binaries that are wrong for Alpine) into
|
|
# the build context. That is what filled the production disk.
|
|
|
|
# Dependencies — reinstalled from the lockfile in the deps stage
|
|
node_modules
|
|
.pnp
|
|
.pnp.*
|
|
.yarn
|
|
|
|
# Build output — regenerated by `npm run build` in the builder stage.
|
|
# .next/dev alone is 1.8 GB of dev-server cache that must never leave the host.
|
|
.next
|
|
out
|
|
build
|
|
dist
|
|
|
|
# VCS + local tooling
|
|
.git
|
|
.gitignore
|
|
.github
|
|
.claude
|
|
.vscode
|
|
.idea
|
|
|
|
# Incremental compiler state (253 KB and host-specific)
|
|
*.tsbuildinfo
|
|
next-env.d.ts
|
|
|
|
# Environment.
|
|
#
|
|
# `.env` IS copied in (see the Dockerfile's runner stage) — it holds the
|
|
# production platform host, which is not a secret, and is what the standalone
|
|
# server reads at boot. Excluding it is what shipped an image with no
|
|
# LOYALY_API_BASE and made every BFF call fail.
|
|
#
|
|
# `.env.*` stays out, and that exclusion is load-bearing: a developer's
|
|
# `.env.local` points LOYALY_API_BASE at http://127.0.0.1:8088, and @next/env
|
|
# loads `.env.local` AHEAD of `.env`. One leaked into the image and the
|
|
# deployed console calls localhost — silently, with no error to read.
|
|
.env.*
|
|
*.pem
|
|
|
|
# Docs and infra that the build does not read
|
|
*.md
|
|
Dockerfile
|
|
.dockerignore
|
|
nginx.conf
|
|
|
|
# Noise
|
|
.DS_Store
|
|
coverage
|
|
npm-debug.log*
|
|
yarn-error.log*
|