Warum ein Headless CMS?
Klassische Content-Management-Systeme koppeln Inhalt und Darstellung fest zusammen. Sobald Content nicht nur auf einer Website, sondern auch in einer App, einem Newsletter oder einem E-Commerce-Shop erscheinen soll, stößt dieses Modell an Grenzen. Ein Headless CMS trennt beides: Redakteure pflegen Inhalte über ein Admin-Panel, Entwickler rufen diese per API ab und stellen sie auf beliebig vielen Kanälen dar.
Ein bewährtes Open-Source-Tool für diesen Ansatz ist Strapi. Über 70.000 GitHub Stars, aktive Entwicklung, ein visueller Content-Type-Builder und automatisch generierte REST- und GraphQL-APIs. Strapi eignet sich besonders für Agenturen, Entwickler und Unternehmen, die strukturierte Inhalte (Produkte, Seiten, Events) an individuelle Frontends liefern.
Diese Anleitung beschreibt zwei Wege zur Installation:
- Weg A: Über Coolify (empfohlen für Einsteiger): Ein-Klick-Installation, automatisches SSL
- Weg B: Über Docker Compose (für mehr Kontrolle): manuelle Konfiguration, volle Flexibilität
Voraussetzungen
- Ein Seed in der dataforest Cloud (empfohlen: 4 CPU, 8 GB RAM; 2 CPU / 4 GB reichen für den Einstieg). Strapi benötigt Arbeitsspeicher für Node.js und die Datenbank. Bei mehr als 10 Content Types oder vielen Medien empfiehlt sich das größere Modell.
- SSH-Zugriff auf den Seed
- Eine eigene Domain (z.B. cms.ihre-firma.de), die per DNS A-Record auf die IP-Adresse Ihres Seeds zeigt. Den A-Record setzen Sie bei Ihrem Domain-Anbieter: Tragen Sie dort die IP-Adresse des Seeds als Ziel für die gewünschte Subdomain ein. Nach dem Setzen kann es bis zu einer Stunde dauern, bis der Eintrag weltweit aktiv ist.
- Für Weg A: Coolify auf dem Seed installiert (siehe Coolify-Guide)
Weg A: Installation über Coolify
Coolify bietet Strapi als Ein-Klick-Service. Wenn Sie Coolify bereits nutzen, ist dies der schnellste Weg.
1. Strapi-Service anlegen
Öffnen Sie das Coolify-Dashboard und navigieren Sie zu Ihrem Projekt. Klicken Sie auf New Resource und wählen Sie Service. In der Service-Liste suchen Sie nach Strapi und wählen es aus.
2. Domain konfigurieren
In den Service-Einstellungen tragen Sie Ihre Domain ein (z.B. cms.ihre-firma.de). Coolify konfiguriert automatisch ein Let's-Encrypt-Zertifikat für HTTPS.
3. Umgebungsvariablen prüfen
Coolify setzt PostgreSQL als Datenbank automatisch auf. Prüfen Sie in den Umgebungsvariablen, dass sichere Passwörter gesetzt sind. Wichtige Variablen:
DATABASE_CLIENT:postgres(von Coolify vorkonfiguriert)DATABASE_PASSWORD: Datenbank-Passwort (ändern Sie den Standardwert)APP_KEYS: Kommagetrennte Schlüssel für Sessions (Coolify generiert diese automatisch)JWT_SECRET: Schlüssel für das JWT-Token der Users-PermissionsADMIN_JWT_SECRET: Schlüssel für das Admin-Panel JWT
4. Service starten
Klicken Sie auf Deploy. Coolify baut das Strapi-Image, startet die Container und konfiguriert SSL. Der erste Start dauert einige Minuten, da Strapi die Datenbank initialisiert und das Admin-Panel baut. Danach ist Ihr CMS unter Ihrer Domain erreichbar.
Weg B: Installation über Docker Compose
Dieser Weg bietet mehr Kontrolle über die Konfiguration und eignet sich, wenn Sie kein Coolify nutzen.
1. Docker installieren
Verbinden Sie sich per SSH mit Ihrem Seed und installieren Sie Docker. Das offizielle Installationsskript erkennt Ihr Betriebssystem automatisch und richtet Docker inklusive Docker Compose ein:
curl -fsSL https://get.docker.com | sh
2. Projektverzeichnis erstellen
Alle Konfigurationsdateien für Strapi werden in einem gemeinsamen Verzeichnis abgelegt:
mkdir -p /opt/strapi && cd /opt/strapi
3. Dockerfile erstellen
Strapi stellt kein offizielles Docker-Image bereit. Stattdessen wird ein eigenes Image gebaut, das die Strapi-Anwendung enthält. Erstellen Sie die Datei Dockerfile:
FROM node:22-alpine AS build
RUN apk add --no-cache build-base python3
WORKDIR /opt/app
RUN npx create-strapi-app@latest . \
--no-run \
--skip-cloud \
--no-example \
--no-git-init \
--typescript \
--non-interactive \
--dbclient=postgres \
--dbhost=127.0.0.1 \
--dbport=5432 \
--dbname=strapi \
--dbusername=strapi \
--dbpassword=placeholder
ENV NODE_OPTIONS=--max-old-space-size=1536
RUN NODE_ENV=production npm run build
FROM node:22-alpine
RUN apk add --no-cache vips-dev
WORKDIR /opt/app
COPY --from=build /opt/app ./
ENV NODE_ENV=production
EXPOSE 1337
CMD ["npm", "run", "start"]
Dieser Multi-Stage-Build trennt den Build-Prozess vom Produktions-Image. Die erste Stufe installiert Strapi und baut das Admin-Panel. Die zweite Stufe enthält nur die lauffähige Anwendung ohne Build-Tools, was das Image kleiner und sicherer macht.
Die Datenbank-Parameter im Build-Schritt (--dbhost, --dbpassword etc.) sind Platzhalter für die Projektinitialisierung. Die tatsächliche Datenbankverbindung wird zur Laufzeit über die Umgebungsvariablen in docker-compose.yml gesetzt. NODE_OPTIONS=--max-old-space-size=1536 erhöht den verfügbaren Arbeitsspeicher für den Build-Prozess des Admin-Panels.
4. Caddyfile erstellen
Als Reverse Proxy kommt Caddy zum Einsatz. Caddy benötigt nur wenige Zeilen Konfiguration und holt automatisch ein Let's-Encrypt-Zertifikat für HTTPS.
Erstellen Sie die Datei Caddyfile:
cms.ihre-firma.de {
reverse_proxy strapi:1337
}
Ersetzen Sie cms.ihre-firma.de durch Ihre Domain.
5. Docker Compose Datei erstellen
Die docker-compose.yml beschreibt alle drei Container und wie sie zusammenarbeiten:
services:
caddy:
image: caddy:2-alpine
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- strapi
strapi:
build: .
restart: always
volumes:
- strapi_uploads:/opt/app/public/uploads
environment:
- NODE_ENV=production
- DATABASE_CLIENT=postgres
- DATABASE_HOST=db
- DATABASE_PORT=5432
- DATABASE_NAME=strapi
- DATABASE_USERNAME=strapi
- DATABASE_PASSWORD=SICHERES_DB_PASSWORT
- JWT_SECRET=LANGER_ZUFAELLIGER_STRING_1
- ADMIN_JWT_SECRET=LANGER_ZUFAELLIGER_STRING_2
- APP_KEYS=KEY1,KEY2,KEY3,KEY4
depends_on:
- db
db:
image: postgres:16-alpine
restart: always
volumes:
- db_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=strapi
- POSTGRES_USER=strapi
- POSTGRES_PASSWORD=SICHERES_DB_PASSWORT
volumes:
strapi_uploads:
db_data:
caddy_data:
caddy_config:
Ersetzen Sie SICHERES_DB_PASSWORT durch ein sicheres Passwort (an beiden Stellen identisch). Generieren Sie die Schlüssel für JWT_SECRET, ADMIN_JWT_SECRET und APP_KEYS mit:
openssl rand -base64 32
Führen Sie den Befehl viermal aus und setzen Sie die Ergebnisse als kommagetrennte Liste für APP_KEYS ein.
Zum Aufbau der Datei:
restart: alwaysstartet jeden Container automatisch neu, falls er abstürzt oder der Server neugestartet wirddepends_onlegt die Startreihenfolge fest: Datenbank vor Strapi, Strapi vor Caddyvolumesspeichern Daten dauerhaft außerhalb der Container. Ohne Volumes gehen Uploads und Datenbankeinträge beim Neustart verloren
Die Umgebungsvariablen im Überblick:
DATABASE_CLIENT=postgreskonfiguriert PostgreSQL als DatenbankJWT_SECRETundADMIN_JWT_SECRETsignieren Authentifizierungs-Tokens. Ohne eigene Werte verwendet Strapi unsichere Standardschlüssel.APP_KEYSwerden für Session-Cookies und CSRF-Schutz verwendet
6. Image bauen und starten
docker compose up -d --build
Die Option --build baut das Strapi-Image beim ersten Start. Der Build-Prozess dauert einige Minuten, da Strapi die Abhängigkeiten installiert und das Admin-Panel kompiliert.
7. Prüfen ob alles läuft
docker compose ps
Alle drei Container (caddy, strapi, db) sollten den Status running zeigen. Falls ein Container nicht startet:
docker compose logs strapi
Strapi ist bereit, wenn im Log Server is running erscheint. Den Status können Sie auch per Health-Check prüfen:
curl -s -o /dev/null -w "%{http_code}" https://cms.ihre-firma.de/_health
Der Endpoint gibt HTTP 204 zurück, sobald Strapi vollständig gestartet ist.
Rufen Sie anschließend https://cms.ihre-firma.de im Browser auf.
Admin-Account erstellen
Beim ersten Aufruf zeigt Strapi ein Registrierungsformular für den Admin-Account. Wählen Sie einen Benutzernamen, eine E-Mail-Adresse und ein sicheres Passwort. Dieser Account hat vollen Zugriff auf das Admin-Panel und alle APIs.
Content Type erstellen
Content Types definieren die Struktur Ihrer Inhalte. Als Beispiel wird ein Content Type "Artikel" erstellt:
- Navigieren Sie im Admin-Panel zu Content-Type Builder
- Klicken Sie auf Create new collection type
- Vergeben Sie den Namen
Article - Fügen Sie Felder hinzu:
title(Text, Required)slug(UID, basierend auf title)content(Rich Text)cover(Media, Single image)publishedAt(DateTime)
- Klicken Sie auf Save
Strapi generiert automatisch REST-Endpoints für den neuen Content Type. GraphQL lässt sich durch Installation des Pakets @strapi/plugin-graphql aktivieren.
REST API testen
Standardmäßig sind alle API-Endpoints geschützt. Für öffentlichen Lesezugriff müssen die Berechtigungen konfiguriert werden:
- Navigieren Sie zu Settings > Roles > Public
- Aktivieren Sie unter
Articledie Berechtigung find und findOne - Speichern Sie die Änderungen
Erstellen Sie einen Test-Artikel im Admin-Panel unter Content Manager > Article > Create new entry. Vergeben Sie einen Titel und Content, dann klicken Sie auf Publish.
Testen Sie die API:
curl https://cms.ihre-firma.de/api/articles
Die Antwort enthält Ihre Artikel als JSON:
{
"data": [
{
"id": 1,
"documentId": "abc123",
"title": "Mein erster Artikel",
"slug": "mein-erster-artikel",
"content": "..."
}
]
}
Backup einrichten
Datenbank-Backup
Bei Weg A (Coolify) können Sie automatische Datenbank-Backups direkt im Coolify-Dashboard konfigurieren.
Bei Weg B erstellen Sie ein regelmäßiges Backup der PostgreSQL-Datenbank. Legen Sie zunächst das Backup-Verzeichnis an:
mkdir -p /opt/backups
Ein einzelnes Backup lässt sich jederzeit manuell erstellen:
docker exec strapi-db-1 pg_dump -U strapi strapi > /opt/backups/strapi-db-$(date +%Y%m%d).sql
Damit das Backup automatisch läuft, richten Sie einen Cronjob ein. Ein Cronjob ist ein zeitgesteuerter Befehl, der vom Betriebssystem regelmäßig ausgeführt wird:
crontab -e
Fügen Sie folgende Zeile hinzu:
0 3 * * * docker exec strapi-db-1 pg_dump -U strapi strapi > /opt/backups/strapi-db-$(date +\%Y\%m\%d).sql
Die fünf Werte 0 3 * * * bedeuten: Minute 0, Stunde 3, jeden Tag, jeden Monat, jeden Wochentag. Das Backup wird also täglich um 03:00 Uhr nachts erstellt.
Upload-Verzeichnis sichern
Hochgeladene Medien liegen im Volume strapi_uploads. Den Speicherort finden Sie mit:
docker volume inspect strapi_strapi_uploads --format '{{ .Mountpoint }}'
Dieses Verzeichnis sollte regelmäßig gesichert werden, zum Beispiel mit rsync auf ein externes System.
Server-Backup über dataforest Cloud
Die dataforest Cloud bietet automatische tägliche Offsite-Backups als zubuchbare Option. Damit lassen sich alle Daten auf Ihrem Seed sichern und jederzeit wiederherstellen. Backups sind nicht standardmäßig aktiv und müssen in der Cloud-Konsole aktiviert werden.
Zusammenfassung
Nach Abschluss dieser Anleitung läuft Strapi als Headless CMS auf Ihrem eigenen Server, per HTTPS erreichbar und mit automatischen Backups abgesichert. Content Types lassen sich visuell definieren, Inhalte per REST API abrufen und an beliebige Frontends liefern.
Weitere Möglichkeiten für Ihren Seed finden Sie in unseren Lösungen und Anleitungen. Wenn Sie zusätzlich ein Publishing-fokussiertes CMS benötigen, beschreibt der Ghost-Guide die Einrichtung eines Blog-CMS mit Content API.