# my-app A Next.js application deployed on a self-hosted infrastructure stack. ## Stack Overview ``` Browser └── Caddy (reverse proxy, TLS termination) ├── my-app.mk360.de → Next.js (Docker, port 3003) ├── git.mk360.de → Gitea (port 3000) ├── coolify.mk360.de → Coolify (port 8000) ├── monitor.mk360.de → Uptime Kuma (10.0.1.7) └── paperclip.mk360.de → Paperclip (port 3100) ``` ### Why Next.js? Next.js provides server-side rendering, file-based routing, and built-in TypeScript support out of the box. It compiles to a [standalone output](https://nextjs.org/docs/app/api-reference/config/next-config-js/output#automatically-copying-traced-files) (`output: "standalone"`) which produces a minimal Docker image (~100 MB) containing only the files needed to run the app — no `node_modules` bloat in the final image. ### Why Coolify? Coolify is a self-hosted deployment platform (similar to Vercel/Heroku) that manages Docker containers, handles rolling updates, and provides a deployment UI and API. It replaces the need for a managed cloud provider, keeping everything on the mk360.de server. The CI/CD pipeline works as follows: ``` git push └── Gitea webhook → Caddy /deploy/my-app → Coolify API └── Coolify clones repo, builds Docker image, rolling update ``` > Note: Coolify's native Gitea webhook endpoint requires OAuth source integration. > The `/deploy/my-app` Caddy route acts as a bridge, injecting the Coolify API > bearer token so Gitea's plain webhook can trigger authenticated deploys. ## Subdomains | Subdomain | Service | Backend | |-----------|---------|---------| | `my-app.mk360.de` | This Next.js app | `127.0.0.1:3003` | | `git.mk360.de` | Gitea — self-hosted Git | `127.0.0.1:3000` | | `coolify.mk360.de` | Coolify — deployment platform | `127.0.0.1:8000` | | `monitor.mk360.de` | Uptime Kuma — uptime monitoring | `10.0.1.7:80` | | `paperclip.mk360.de` | Paperclip | `127.0.0.1:3100` | All subdomains are served over HTTPS via Caddy with automatic TLS certificates. ## Build & Deploy The app is built using a multi-stage Dockerfile with BuildKit cache mounts: - **`deps` stage** — installs npm packages, cached via `--mount=type=cache,target=/root/.npm` - **`builder` stage** — runs `next build`, cached via `--mount=type=cache,target=/app/.next/cache` - **`runner` stage** — minimal Alpine image, copies only the standalone output This keeps subsequent deploys fast even though Coolify builds with `--no-cache` by default, since BuildKit cache mounts persist independently of the layer cache.