MEGAINFRA-WEBAPP/COOLIFY.md
SJCoetz 7d2684f321 Fix Coolify build: skip postinstall in deps stage
The postinstall hook runs scripts/patch-next-dev-blocker.cjs, but at
that point in the Docker build only package.json and package-lock.json
have been copied — the scripts/ directory isn't there yet, so the
hook fails with MODULE_NOT_FOUND.

The patch is dev-only (it mutates Next 16's dev-only cross-site
guard, which is never loaded in production), so it's safe to skip
during the Docker build. Two changes:

1. Dockerfile: use 'npm ci --ignore-scripts' in the deps stage so
   the postinstall hook doesn't run before the scripts/ directory
   is available.
2. scripts/patch-next-dev-blocker.cjs: bail out cleanly with exit 0
   when node_modules/next is missing, so the script is also safe to
   run in any intermediate state.
2026-08-09 02:29:48 +02:00

3.4 KiB

Deploying to Coolify

This project ships with a Dockerfile and a docker-compose.yml that work with Coolify v4 out of the box.

Quick start

  1. Create a new Application in Coolify

    • Source: Git Repository
    • Repository URL: http://forgejo-b82b4lpyyzyg40thdsjdd38i.163.245.214.68.sslip.io/David/MEGAINFRA-WEBAPP.git
    • Branch: main
    • Build Pack: Dockerfile
    • Port: 3000
  2. Set the environment variables (Coolify → Application → Environment Variables):

    Key Value Notes
    NEXT_PUBLIC_APP_PIN 2468 The PIN the login screen accepts. Change this in production.
    NEXT_PUBLIC_APP_NAME MEGA INFRASTRUCTURE Shown on the lock screen.
    NEXT_PUBLIC_DEFAULT_THEME light light or dark.
  3. Expose the port — Coolify's Traefik will route traffic to the container on port 3000. The server binds to 0.0.0.0 so it accepts connections from any host.

  4. Healthcheck — GET /api/health returns a 200 JSON payload with the live counts and is wired as the Docker HEALTHCHECK.

What the Dockerfile does

  • Multi-stage build: it caches npm ci separately from the source copy, so unchanged dependencies don't invalidate the build layer.
  • Next.js standalone output: with output: "standalone" in next.config.js, the build produces a self-contained .next/standalone/ directory with a trimmed node_modules and a server.js entry point.
  • Non-root runtime: the server runs as a dedicated nextjs user.
  • PWA service worker: next build regenerates public/sw.js, public/workbox-*.js and public/manifest.json from the @ducanh2912/next-pwa plugin. The .dockerignore deliberately excludes the pre-built versions so the build always ships the right hashes for the new release.

Build-time concern: the dev-only patch

scripts/patch-next-dev-blocker.cjs patches Next 16's dev-only cross-site guard so next dev accepts requests from any host (LAN, tunneled domains, etc.). The patched module is only loaded by next dev — never by the production server — so the Dockerfile runs npm ci --ignore-scripts in the deps stage to skip the postinstall hook entirely. The patch script is also self-resilient: it detects when node_modules/next is absent and exits 0 cleanly.

Environment variables

Anything prefixed with NEXT_PUBLIC_ is inlined into the client bundle at build time. If you change NEXT_PUBLIC_APP_PIN, you must rebuild the image — Coolify will not pick up the change otherwise.

Variable Required Default Purpose
NEXT_PUBLIC_APP_PIN Yes 2468 Login PIN.
NEXT_PUBLIC_APP_NAME No MEGA INFRASTRUCTURE Brand name on the lock screen.
NEXT_PUBLIC_DEFAULT_THEME No light Default theme before user preference is read from localStorage.
NEXT_PUBLIC_API_BASE_URL No unset When you wire PocketBase, point this at the backend.
POCKETBASE_URL No unset Backend URL for server-side requests.
POCKETBASE_TOKEN No unset Server-side auth token.

Useful Coolify probes

Probe URL Expects
Liveness GET /api/health 200 with JSON body
Auth gate GET /login 200 HTML

Local smoke test

docker compose up --build
# wait ~2 minutes for the first build
open http://localhost:3000/login
# default PIN: 2468