mega-plant/COOLIFY.md

98 lines
3.6 KiB
Markdown
Raw Normal View History

2026-09-12 10:05:43 +00:00
# Deploying Mega Plant to Coolify
## The one thing that catches everyone
`NEXT_PUBLIC_PB_URL` must be set as a **Build Argument**, not only as an
environment variable.
Next.js compiles `NEXT_PUBLIC_*` values into the JavaScript the browser
downloads. That happens at `npm run build`, inside the Docker build. Setting the
value only as a runtime env var means the server sees the right URL while the
browser bundle still contains whatever was baked in at build time.
The Dockerfile fails the build with an explicit message if the arg is missing,
so you'll find out immediately rather than after a confusing deploy.
## Setup
**1. Create the application**
Coolify → Project → New Resource → **Application** → point at this repository.
Build Pack: **Dockerfile**. Port: **3000**.
**2. Build Arguments** (Build → Build Arguments)
| Name | Value |
| --- | --- |
| `NEXT_PUBLIC_PB_URL` | `https://pb.mega.plant.example` |
**3. Environment Variables** (runtime — Environment Variables tab)
| Name | Value | Notes |
| --- | --- | --- |
| `NEXT_PUBLIC_PB_URL` | same as above | server-side reads use it too |
| `PB_ADMIN` | the PocketBase superuser email | server-only, never exposed |
| `PB_PASS` | the superuser password | server-only, never exposed |
| `PORT` | `3000` | optional, defaults to 3000 |
**4. Health check**
Coolify → Health Checks → path `/api/health`, port `3000`. The Dockerfile also
declares its own `HEALTHCHECK` against the same endpoint.
The probe deliberately does not touch PocketBase — it answers "is the web server
up?". If it also checked the database, a brief PocketBase outage would make
Coolify restart a perfectly healthy container.
**5. Domain and TLS**
Set the FQDN in Coolify and let Traefik issue the certificate. **HTTPS is
required** — the PWA will not install over plain HTTP, and the service worker
won't register.
## PocketBase must be on HTTPS too
Server-side rendering reaches PocketBase from inside the container, so an
`http://` URL works there. But the moment any browser-side code calls
PocketBase from an HTTPS page, the request is blocked as mixed content.
Put PocketBase behind TLS. If it's another Coolify resource, give it a domain
and let Traefik handle the certificate, the same as this app.
## Before the first deploy
- [ ] **Rotate the PocketBase superuser password.** The old one
(`plant@megainfra.co.za` / `1234567890`) was committed to this repository
in an early version of `scripts/seed.mjs`. Treat it as compromised.
- [ ] Confirm `.env.local` is not committed (it's in `.gitignore`).
- [ ] Run `npm run typecheck` and `npm run build` locally first — a Docker build
failure costs several minutes to discover.
## Test the image locally
```bash
docker build --build-arg NEXT_PUBLIC_PB_URL=https://pb.mega.plant.example -t mega-plant .
```
```bash
docker run --rm -p 3000:3000 -e PB_ADMIN=you@example.com -e PB_PASS=secret mega-plant
```
Then check the health endpoint:
```bash
curl -s localhost:3000/api/health
```
## Notes
- **`--webpack` is not optional.** `@ducanh2912/next-pwa` is Webpack-only and
generates `public/sw.js`. `package.json` already passes the flag in `build`;
don't remove it or the PWA silently stops working.
- **`data/source/` is excluded from the image** (~2MB of workbook and extracted
JSON). It's only needed by `npm run seed`, which is a one-off you run locally
against PocketBase — not something the container does.
- **Seeding is not part of deployment.** The container never writes to
PocketBase on boot. Run `npm run seed` deliberately, from your machine.
- The image runs as a non-root `nextjs` user on Node 20 Alpine.