DevOps-Pipeline mit Coolify, Next.js & GitHub Actions — Auto-Deploy ohne Vendor-Lockin

Komplette CI/CD-Pipeline für Next.js auf einem self-hosted Coolify-Server: Push auf main, Tests laufen, Build wird gebaut und live ist neu — ohne Vercel-Abhängigkeit. Inklusive Secrets-Management, Preview-Deployments und den Pitfalls aus dem produktiven Einsatz.

19. Mai 20269 min Lesezeit702 Wörter

Warum eigene Pipeline?

Vercel ist großartig — bis die Rechnung kommt, Edge-Functions kostenpflichtig werden oder die Compliance-Abteilung nachfragt, wo die Daten liegen. Coolify auf einem 20 €/Monat VPS ersetzt 90 % von Vercel/Render/Heroku für Side-Projects und Mid-Size-Apps, ohne dass man Kubernetes lernen muss.

Dieser Artikel zeigt die komplette Pipeline, die ich für diese Website selbst nutze: Push auf main → GitHub Actions checkt Code → Coolify pullt, baut und deployed. Ohne manuelle Schritte.

Die Architektur

GitHub push → GitHub Actions (lint/typecheck/build-test)
            → Coolify Webhook (deploy trigger)
            → Coolify pulls repo, runs docker build
            → Container Swap (zero-downtime)
            → Health-Check, dann Cutover

Schritt 1: Coolify-Projekt aufsetzen

In Coolify ein neues Service-Projekt anlegen, Repo verbinden (Personal Access Token mit repo-Scope). Coolify generiert automatisch einen Webhook — der wird gleich gebraucht.

Wichtig: Dockerfile-basiert deployen, nicht Buildpacks. Buildpacks sind eine Black-Box, Dockerfile gibt volle Kontrolle. Mein Minimal-Stack für Next.js 16:

FROM node:24-alpine AS deps
RUN corepack enable
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

FROM node:24-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ARG NEXT_PUBLIC_SUPABASE_URL
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY
RUN pnpm build

FROM node:24-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]

Multi-Stage spart Image-Size. output: 'standalone' in next.config.js aktivieren — sonst wird das Image 800 MB statt 200 MB.

Schritt 2: GitHub Actions als Quality-Gate

# .github/workflows/quality.yml
name: Quality Gate
on:
  push:
    branches: [main]
  pull_request:

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v3
        with: { version: 9 }
      - uses: actions/setup-node@v4
        with: { node-version: 24, cache: pnpm }
      - run: pnpm install --frozen-lockfile
      - run: pnpm exec tsc --noEmit
      - run: pnpm lint
      - run: pnpm test --if-present

Wichtig: Den eigentlichen pnpm build macht Coolify selbst. GitHub Actions ist nur das Quality-Gate. Doppelt zu bauen wäre Zeitverschwendung.

Schritt 3: Webhook-Trigger nach erfolgreichem Check

# .github/workflows/deploy.yml
name: Deploy
on:
  workflow_run:
    workflows: [Quality Gate]
    types: [completed]
    branches: [main]

jobs:
  trigger:
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Coolify deploy
        run: |
          curl -X POST \
            -H "Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}" \
            "${{ secrets.COOLIFY_WEBHOOK_URL }}"

Coolify-Webhook + API-Token in Coolify-UI generieren, als GitHub-Secret hinterlegen. Fertig — deploys laufen nur, wenn der Quality-Gate grün war.

Schritt 4: Secrets richtig managen

Drei Ebenen Secrets:

  1. GitHub Actions Secrets — nur für CI (Coolify-Webhook, Test-Keys)
  2. Coolify Environment Variables — Runtime-Secrets (SUPABASE_SERVICE_ROLE_KEY, OPENAI_API_KEY). Build-time-Secrets als Build Args markieren.
  3. NEVER: Secrets im Repo. Auch nicht in .env.example — nur Variablen-Namen, keine Werte.

Für NEXT_PUBLIC_*-Variablen aufpassen: die landen im Client-Bundle. Niemals Service-Keys mit NEXT_PUBLIC_* prefixen.

Pitfalls aus der Praxis

  • Build-Cache invalidiert nicht — wenn pnpm-lock.yaml sich ändert, aber Coolify den alten node_modules-Layer cached, gibt's komische Fehler. Lösung: in Coolify "Force rebuild" einmal auslösen.
  • DNS-TTL zu hoch — bei Domain-Wechsel oder Cert-Renew dauert's länger als nötig. TTL auf 300 s setzen.
  • Hung Deploys — wenn der neue Container startet aber Health-Check fehlschlägt, blockiert Coolify den Swap. /api/health-Endpoint einbauen, der 200 OK liefert sobald die App ready ist.
  • Out-of-Memory beim Build — Next.js braucht ~2 GB RAM zum Bauen. 1-Core-VPS reicht nicht. Mindestens 4 GB RAM einplanen oder einen separaten Build-Server nutzen.
  • Container restartet endlos — meistens fehlende ENV-Variable. Coolify-Logs im Detail anschauen, nicht nur den Status.

Preview-Deployments per Branch

Coolify unterstützt "Preview Deployments" — jeder PR bekommt eine eigene URL. Aktivieren in Coolify, dann werden Branches automatisch als Subdomains deployed (pr-42.preview.deine-domain.de).

Cleanup: alte Preview-Container nach PR-Merge automatisch löschen, sonst läuft der Server voll. Coolify-Setting: "Auto-delete after merge".

Wann ist Vercel/Render trotzdem besser?

  • Bei extrem viel Traffic oder globaler Edge-Verteilung — Coolify ist single-region
  • Wenn du keinen Bock auf VPS-Wartung hast und das Budget egal ist
  • Bei strengen Compliance-Anforderungen, die einen zertifizierten Provider verlangen (SOC 2, ISO 27001)

Für Solo-Devs und kleine Teams mit predictable Traffic: Coolify spart 200–500 € im Monat ohne spürbaren DX-Verlust.

Nächste Schritte

Bei Bedarf an einer kompletten DevOps-Pipeline für deine bestehende Stack: Anfrage — meistens in einem Sprint einsatzbereit.

In Praxis

Verwandte Artikel

Neue Artikel via RSS abonnieren