
Wie du Payload CMS in Docker ausführst

Lerne, wie du Payload CMS mit Docker containerisierst und bereitstellst, einschließlich Lösungen für häufige Probleme.
Payload ist ein Open Source Backend Framework und wird hauptsächlich als Content Management System verwendet.
Du kannst Docker verwenden, um deine eigene Payload-Instanz auf Sliplane zu betreiben. Als ich jedoch das Dockerfile verwendete, das durch pnpx create-payload-app
erstellt wird, funktionierte es bei mir nicht sofort und ich musste einige Anpassungen und Einstellungen vornehmen, um Payload zum Laufen zu bringen.
Hier ist, wie du Payload mit Docker ausführen kannst:
Voraussetzungen
NodeJs und Docker sollten auf deinem System installiert sein. Für die Demo verwende ich pnpm als Package Manager, also stelle sicher, dass du es ebenfalls installierst oder passe die Installationsanweisungen an deinen bevorzugten Package Manager an.
In meinem Fall verwendete ich:
- Node Version: v22.12.0
- pnpm Version: 9.13.2
Eine neue Payload App erstellen
Öffne ein neues Terminal im übergeordneten Ordner, wo dein Payload-Projekt erstellt werden soll. Führe den Installationsassistenten aus mit:
# npx
npx create-payload-app
# oder pnpx
pnpx create-payload-app
Du wirst durch eine Reihe kurzer Fragen geführt, ich verwende:
- "Payload Demo" als meinen Projektnamen
- erstelle ein leeres Projekt
- verwende MongoDB als meine Datenbank und nutze zunächst die Standard-Verbindungseinstellungen
- und pnpm als Package Manager
Um Payload in ein bestehendes Projekt zu installieren, folge bitte den Installationsanweisungen in der offiziellen Payload Dokumentation.
Nachdem der Assistent fertig ist, können wir sehen, dass das Projekt bereits ein Dockerfile enthält. Als ich jedoch versuchte, dieses Dockerfile zu verwenden, stieß ich auf mehrere Probleme, die verhinderten, dass es in meiner Umgebung ordnungsgemäß funktionierte.
Probleme, die ich antraf
Beim Versuch, das generierte Dockerfile auszuführen, stieß ich auf einige Probleme:
- Nicht fixierte pnpm Version - Das Dockerfile spezifizierte keine bestimmte pnpm Version, was dazu führte, dass meine Docker Builds fehlschlugen
- Fehlender Standalone Mode - Meine Builds schlugen auch fehl, weil Next.js nicht für Standalone Output konfiguriert war
- Public Folder Probleme - Das Dockerfile versuchte einen Public Folder zu kopieren, der am Anfang in meinem Setup nicht existierte
- Datenbankverbindungsprobleme - Ich übersah den
authSource
Verbindungsparameter in der MongoDB Connection URI - Datei-Upload Berechtigungen - Media Uploads schlugen wegen falscher Ordnerberechtigungen fehl
Lass mich dir zeigen, wie ich diese Probleme eines nach dem anderen gelöst habe.
Mein korrigiertes Dockerfile
Hier ist das korrigierte Dockerfile, das die Probleme löste, auf die ich gestoßen bin:
# Um dieses Dockerfile zu verwenden, musst du `output: 'standalone'` in deiner next.config.mjs Datei setzen.
# Von https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
FROM node:22.12.0-alpine AS base
# Dependencies nur installieren wenn nötig
FROM base AS deps
# Siehe https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine um zu verstehen warum libc6-compat benötigt werden könnte.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Dependencies basierend auf dem bevorzugten Package Manager installieren
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && corepack prepare [email protected] --activate && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Source Code nur rebuilden wenn nötig
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Next.js sammelt völlig anonyme Telemetriedaten über die allgemeine Nutzung.
# Mehr dazu hier: https://nextjs.org/telemetry
# Kommentiere die folgende Zeile aus, falls du Telemetrie während des Builds deaktivieren möchtest.
ENV NEXT_TELEMETRY_DISABLED 1
RUN \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && corepack prepare [email protected] --activate && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
# Production Image, alle Dateien kopieren und next ausführen
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
# Kommentiere die folgende Zeile aus, falls du Telemetrie während der Laufzeit deaktivieren möchtest.
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Entferne diese Zeile wenn du diesen Ordner nicht hast
COPY --from=builder /app/public ./public
# Korrekte Berechtigung für Prerender Cache setzen
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Output Traces automatisch nutzen um Image-Größe zu reduzieren
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
RUN mkdir -p media && chown -R nextjs:nodejs media
USER nextjs
EXPOSE 3000
ENV PORT 3000
# server.js wird von next build aus dem Standalone Output erstellt
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js
Build und Ausführung
So kannst du deine Payload CMS Anwendung builden und ausführen:
# Docker Image builden
docker build -t payload-cms .
# Container ausführen
docker run -p 3000:3000 \
-e DATABASE_URI=mongodb://your-mongo-host:27017/payload?authSource=admin \
-e PAYLOAD_SECRET=your-secret-key \
payload-cms
Hinweis: Wenn du hochgeladene Dateien persistent speichern möchtest, kannst du ein Volume zu
/app/media
mounten, jedoch möchtest du in einem produktionsreiferen Setup vielleicht eine Object Storage Lösung verwenden
pnpm Version fixieren
Um das pnpm Versionsproblem zu lösen, fixierte ich die spezifische Version im Dockerfile in den deps und builder Stages:
RUN corepack enable pnpm && corepack prepare [email protected] --activate
Dies stellt sicher, dass dieselbe pnpm Version konsistent in allen Umgebungen verwendet wird.
Next.js für Standalone Output konfigurieren
Du musst auch deine next.config.mjs
Datei aktualisieren, um den Standalone Output Mode zu aktivieren:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
// ... andere Konfigurationsoptionen
}
export default nextConfig
Dies teilt Next.js mit, eine Standalone Version deiner Anwendung zu erstellen, die alle notwendigen Dependencies enthält.
Public Folder einrichten
Falls dein Projekt noch keinen Public Folder hat, erstelle einen:
mkdir public
echo "" > public/.gitkeep
Dies hilft sicherzustellen, dass der COPY Befehl im Dockerfile nicht fehlschlägt.
Datenbank-Konfiguration
Ich verwendete MongoDB in einem Container und musste den authSource=admin
Parameter in die Connection URI einbeziehen, um mich verbinden zu können:
DATABASE_URI=mongodb://username:password@localhost:27017/payload?authSource=admin
Datei-Upload Berechtigungen
Ich hängte den Media Folder über ein Volume Mount an den Docker Container an. Dies ermöglicht es dir, hochgeladene Dateien außerhalb des Containers persistent zu speichern.
Damit Uploads korrekt funktionieren, musste ich sicherstellen, dass der Media Folder die richtigen Berechtigungen hatte, die ich im Dockerfile setzte mit:
RUN mkdir -p media && chown -R nextjs:nodejs media
Dies erstellt das Media Directory und setzt die korrekte Eigentümerschaft, sodass der nextjs User hochgeladene Dateien dorthin schreiben kann.
Object Storage für Media Dateien
Irgendwann möchtest du vielleicht Object Storage für Media Dateien konfigurieren, anstatt sie in einem Volume zu speichern:
// payload.config.ts
import { s3Adapter } from '@payloadcms/plugin-cloud-storage/s3'
export default buildConfig({
plugins: [
cloudStorage({
collections: {
media: {
adapter: s3Adapter({
config: {
endpoint: process.env.S3_ENDPOINT,
region: process.env.S3_REGION,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
},
bucket: process.env.S3_BUCKET,
}),
},
},
}),
],
// ... Rest deiner Config
})
Auf Sliplane deployen
Du kannst deine Payload CMS Instanz auf Sliplane deployen, indem du ein paar einfache Schritte befolgst:
- Erstelle ein neues Projekt und gib ihm einen Namen deiner Wahl
- Als nächstes werden wir eine MongoDB Datenbank deployen
- Navigiere in das Projekt und klicke "Service deployen", wähle einen Server und wähle das MongoDB Preset. Du kannst den Service "privat" machen, da wir ihn nicht dem öffentlichen Internet aussetzen wollen
- Deploye die Datenbank, alternativ kannst du die Verbindungseinstellungen wie User, Passwort und Datenbankname anpassen
- Als nächstes werden wir Payload CMS deployen und es mit der MongoDB Instanz verbinden, die wir gerade erstellt haben
- Im Projekt klicke erneut "Service deployen", wähle denselben Server, auf dem deine Datenbank läuft und wähle "Repository" als Deployment-Methode
- Im Repository URL Feld, suche nach deinem Payload CMS Repository. Falls es nicht in der Liste erscheint, stelle sicher, dass du Sliplane Zugriff auf das Repo gewährt hast mit dem "Repository Zugriff konfigurieren" Button
- Füge ein Volume hinzu, gib ihm einen Namen deiner Wahl und mounte es zu
/app/media
- Füge die
PAYLOAD_SECRET
undDATABASE_URI
Umgebungsvariablen hinzu.PAYLOAD_SECRET
ist ein beliebiges Passwort. Die Datenbank URI sollte so aussehen:mongodb://username:password@mongodb:27017/payload?authSource=admin
- Du findest alle Verbindungseinstellungen wie User, Passwort, Datenbank und internen Hostnamen in den MongoDB Service Einstellungen - Klicke "Deployen" und warte, bis das Deployment abgeschlossen ist
Fazit
Payload CMS in Docker auszuführen erfordert einige Konfigurationsanpassungen über das Standard-Setup hinaus.
Die wichtigsten Fixes beinhalten das Fixieren der pnpm Version, das Aktivieren des Next.js Standalone Mode, das Setzen korrekter Dateiberechtigungen und optional das Konfigurieren von Object Storage für den Produktionseinsatz.