Files
2026-06-30 11:13:06 +00:00

2.6 KiB

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 (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.