Skip to content

fix: deploy on Dokploy from .env settings with one lean image - #53

Open
voidash wants to merge 4 commits into
mainfrom
chore/lean-runtime-image
Open

voidash wants to merge 4 commits into
mainfrom
chore/lean-runtime-image

Conversation

@voidash

@voidash voidash commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

What changed

Makes the Docker deployment work from the settings a hosting platform provides, and ships one 286 MB image instead of a 341 MB app image plus a 2.07 GB migration image.

  • Settings from .env. Compose required apps/api/.env.local and passed nothing else into the containers. A deployment that supplies settings the usual way, in a .env next to docker-compose.yml, could not start: Compose refused to run without the file, and once it existed the app received only DATABASE_URL and STORAGE_DIR, so it stopped with "Invalid environment configuration". Both files are now optional env files for the app and migrate; .env.local wins where both set a value.

  • Production stack for Dokploy. prod-docker-compose.yaml follows Dokploy's Docker Compose rules: settings load from the .env Dokploy writes, the app only exposes 3000 and joins dokploy-network for Traefik, Postgres stays on the stack's own network, data is in named volumes, no container_name. Compose refuses to deploy without AUTH_URL or POSTGRES_PASSWORD, and there is no default database password. docs/deployment.md has step-by-step Dokploy instructions.

  • Database credentials from .env. POSTGRES_USER, POSTGRES_PASSWORD and POSTGRES_DB can be set there (defaults unchanged), and DATABASE_URL is built from them.

  • No separate migration image. The migration, project-init and GitHub-sync scripts are bundled with bun build into three single files (1.1 MB in total) that plain Node runs from the app image. The migrate service in Compose uses the same image with node scripts/migrate.js, and reads the env file so one-off tasks get GITHUB_TOKEN.

  • One migrator everywhere. db:migrate uses Drizzle's built-in migrator, the one the tests already used, instead of drizzle-kit migrate. Both record applied migrations in the same table, so existing databases carry on as they are.

  • No unused image optimiser. sharp and libvips (about 19 MB) are left out of the standalone output; no page uses next/image, and images.unoptimized is set.

  • No package managers (npm, yarn, corepack) in the runtime image.

  • Base images pinned by digest.

  • Configurable ports. DB_PORT and API_PORT override the host ports in compose.yaml (defaults unchanged: 5432, 3000), so the stack can run beside another Postgres or app. This was chore: make compose ports configurable #38, folded in here.

Closes #52

Contract impact

  • No changes to packages/api-contract

Checks

  • bun run lint
  • bun run typecheck
  • bun run test (150 passed)
  • bun run build
  • CI's migration step (bun run db:migrate on a clean database) with the new script

Tested with Docker from a clone of this branch:

Check Result
Image 286 MB (was 341 MB + 2.07 GB); no npm/yarn/corepack, no sharp; runs as node
docker compose up on a fresh database migrations applied, app healthy in 27 s
node scripts/init-project.js, node scripts/sync-github.js in the image project initialised, issues synced
Pages and API (/en, /ne, members, issues, project, /v1/*, /health) 200; HTML byte-for-byte the same size as from the old image
Browser: static assets all 10 same-origin images, fonts and stylesheets load
DB_PORT=15432 API_PORT=13000 docker compose up -d beside a stack holding 5432 and 3000 runs; defaults unchanged
Platform style: only a root .env (custom POSTGRES_PASSWORD, AUTH_URL), no .env.local settings reach the app, migrations run, app healthy, callback is https://devnepal.gov.np/..., pages 200
prod-docker-compose.yaml without POSTGRES_PASSWORD or AUTH_URL refuses to deploy, naming the missing setting
prod-docker-compose.yaml with Dokploy-style .env, on a dokploy-network no host ports; app on both networks, Postgres only on the stack network and unreachable from dokploy-network; callback https://devnepal.gov.np/...; pages 200; node scripts/init-project.js in the app container works; data survives a redeploy
Local style: only apps/api/.env.local unchanged: its values reach the app, default credentials
drizzle-kit migrate then this image's migration on the same database nothing applied twice (3 migration rows)
New migrator then drizzle-kit migrate, and the reverse, on fresh databases identical migration history and tables

Notes for reviewers

outputFileTracingExcludes names Bun's node_modules/.bun/ layout explicitly, because globs do not match that hidden directory. If the package manager changes, those two paths need updating; the build would then include sharp again, not break.

Foundation checklist

  • Commits signed off (git commit -s)
  • Works in both English and Nepali where applicable (no text changes)
  • No secrets or real personal data anywhere in the diff
  • Documentation updated (docs/deployment.md, .env.example)

@voidash
voidash changed the base branch from chore/configurable-compose-ports to main September 28, 2026 06:27
@voidash voidash changed the title chore: ship one lean runtime image chore: ship one lean runtime image with configurable ports Sep 28, 2026
@abhiyandhakal

Copy link
Copy Markdown
Collaborator

@voidash seems like there is a merge conflict.

The host ports for Postgres and the app were fixed at 5432 and 3000.
They can now be overridden with DB_PORT and API_PORT; the defaults are
unchanged. Also document that the migrate image runs one-off tasks such
as db:init, and fix a Dockerfile comment that still mentioned the
removed design CSS and fonts.

Signed-off-by: voidash <ashish.thapa477@gmail.com>
Migrations ran from a separate image that was the whole build stage,
dev dependencies included (2.07 GB), as root. The migration, project-init
and GitHub-sync scripts are now bundled into single files that Node runs
from the app image, so the migrate service uses the same image and the
separate one is gone. db:migrate uses the same Drizzle migrator, which
shares its history table with drizzle-kit.

The runtime image also leaves out the unused image optimiser (sharp and
libvips, about 19 MB; no page uses next/image) and the package managers,
and both base images are pinned by digest.

Signed-off-by: voidash <ashish.thapa477@gmail.com>
Compose required apps/api/.env.local and passed nothing else into the
containers, so a deployment that supplies settings the usual way, in a
.env next to docker-compose.yml, could not start: Compose refused to run
without the file, and once it existed the app still received only
DATABASE_URL and STORAGE_DIR. Both files are now optional env files for
the app and migrate services; .env.local wins where both set a value.

The Postgres credentials can also be set from .env (POSTGRES_USER,
POSTGRES_PASSWORD, POSTGRES_DB), with the previous values as defaults,
and DATABASE_URL is built from them.

Signed-off-by: voidash <ashish.thapa477@gmail.com>
@voidash
voidash force-pushed the chore/lean-runtime-image branch from 790297a to b732659 Compare September 30, 2026 18:46
@voidash voidash changed the title chore: ship one lean runtime image with configurable ports fix: deploy from .env settings with one lean image Sep 30, 2026
prod-docker-compose.yaml runs Postgres, the one-shot migration and the
app the way Dokploy expects: settings load from the .env Dokploy writes,
the app only exposes port 3000 and joins dokploy-network for Traefik,
Postgres stays on the stack's own network, data is in named volumes,
and no service sets container_name. Compose refuses to deploy without
AUTH_URL or POSTGRES_PASSWORD, and there is no default database
password. The deployment guide gets step-by-step Dokploy instructions.

Signed-off-by: voidash <ashish.thapa477@gmail.com>
@voidash voidash changed the title fix: deploy from .env settings with one lean image fix: deploy on Dokploy from .env settings with one lean image Oct 3, 2026
Comment thread docker-compose.yml
POSTGRES_USER: refined
POSTGRES_PASSWORD: refined
POSTGRES_DB: refined
POSTGRES_USER: ${POSTGRES_USER:-refined}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is likely not reading .env.local

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compose deployment cannot use platform settings and needs a 2 GB migration image

2 participants