Dieses Repo https://github.com/alandolsi/typo3-starter ist ein „Cloud-Ready“ TYPO3 v13 LTS Boilerplate, das lokale Entwicklung mit DDEV und ein Docker-basiertes Deployment über Coolify kombiniert. Dazu kommen automatische Umgebungserkennung (DDEV vs. Production), 12-Factor-App-Prinzipien, eine CI/CD-Pipeline mit GitHub Actions, Code-Quality-Checks (PHP-CS-Fixer, PHPStan) sowie Security Audits. In diesem Artikel gehst du Schritt für Schritt von „Repo klonen“ bis „Rollback per Image-Tag“ und bekommst dabei konkrete Hinweise, wo es in der Praxis typischerweise hakt. Stand: 2026-01-05.
1) Überblick: Was du bekommst (und was nicht)
Der Starter setzt auf TYPO3 v13 LTS, PHP 8.3, Apache und MariaDB 10.11. Lokal läuft alles über DDEV, in Production über Coolify mit Dockerfile-Build. Die Pipeline baut und prüft bei jedem Push/PR und deployt bei Push auf main via Webhook. Releases werden über Git Tags (v*) als Docker Images in die GitHub Container Registry (ghcr.io) veröffentlicht und zusätzlich als GitHub Release markiert.
Wichtig für die Erwartungshaltung: Das Repo beschreibt keine eigene Object-Storage-Integration. Wenn du Assets/Uploads in ein S3-kompatibles Object Storage auslagern willst (z.B. Cloudflare R2), ist das ein ergänzender Schritt, den du in TYPO3 (und ggf. im Deployment) separat umsetzen musst. Der Starter liefert dir dafür aber die richtigen Leitplanken: env-basierte Konfiguration, stateless Container, klare Trennung von Build/Release/Run.
2) Voraussetzungen lokal: DDEV + Composer
Du brauchst DDEV (für die lokale Umgebung) und Composer. DDEV kapselt PHP, Webserver und DB, sodass du nicht mit lokalen PHP-Versionen oder Datenbankdiensten kämpfen musst. In Teams ist das der größte Hebel für „Dev/Prod Parity“: alle arbeiten mit identischer Basis.
3) Projekt klonen und lokal starten (DDEV)
Der schnellste Einstieg folgt exakt dem README-Flow. Nach dem Start kannst du Frontend und Backend direkt öffnen und typische TYPO3-Tasks (z.B. Cache flushen) über ddev ausführen.
git clone https://github.com/alandolsi/typo3-starter.git
cd typo3-starter
ddev start
ddev launch
ddev launch /typo3
ddev typo3 cache:flush4) Projektstruktur verstehen: Wo du was anfasst
Bevor du Anpassungen machst, lohnt sich ein kurzer Blick auf die Struktur, weil sie die spätere Wartbarkeit bestimmt:
- .ddev/: lokale DDEV-Konfiguration inkl. Provider für Production-Pull
- .github/workflows/: CI und Release Pipeline
- config/system/: Basis- und umgebungsspezifische TYPO3-Konfiguration (settings.php, additional.php)
- packages/site_package/: Site Package (Branding, TypoScript etc.)
- public/: Document Root
- var/: Cache/Logs/Sessions (in Production wichtig bzgl. Permissions)
- Dockerfile: Produktions-Image
Die Trennung von „App-Code“ (Repo) und „Config“ (Environment Variables) ist zentral für 12-Factor. Du solltest vermeiden, Secrets oder host-spezifische Werte in PHP-Dateien zu hardcoden.
5) Automatische Umgebungserkennung (DDEV vs. Production)
Der Starter wirbt mit automatischer Umgebungserkennung. Praktisch bedeutet das: lokale Defaults (DDEV) und Production-Defaults (Coolify/Docker) werden unterschiedlich behandelt, ohne dass du ständig manuell umschalten musst. In Coolify setzt du explizit TYPO3_CONTEXT=Production und zusätzlich IS_DOCKER_ENV=true. Lokal übernimmt DDEV das Umfeld.
Caveat: Achte darauf, dass du nicht versehentlich Production-Context lokal aktivierst (oder umgekehrt). TYPO3 verhält sich je nach Context deutlich anders (Caching, Error-Handling, Debugging). Wenn du „komische“ Cache-Effekte oder fehlende Fehlermeldungen siehst, ist das der erste Check.
6) Production-Daten lokal synchronisieren (DDEV Pull Provider für Coolify)
Ein echtes Praxis-Feature ist der DDEV Provider, um Datenbank und Dateien aus Production zu ziehen. Das ist Gold wert für Debugging, Content-Checks oder reproduzierbare Bugfixes. Der Ablauf ist bewusst simpel: Beispiel-Env kopieren, Credentials eintragen, dann pullen.
cp .ddev/.env.coolify.example .ddev/.env.coolify
ddev pull coolifyCaveat: Behandle die Datei .ddev/.env.coolify wie ein Secret. Sie gehört nicht ins Repo. Außerdem: Ein Pull überschreibt lokal Daten. Wenn du lokale Änderungen an Inhalten/Uploads hast, sichere sie vorher (z.B. DB dump oder Kopie des Files-Verzeichnisses).
7) Deployment mit Coolify: Dockerfile, Env Vars, Post-Deploy
Coolify baut das Image aus dem Dockerfile und startet es als Container. Der Starter ist so ausgelegt, dass du möglichst wenig „Server-Handarbeit“ brauchst. Die Kernschritte im README sind:
- Repository in Coolify hinzufügen
- Build-Methode: Dockerfile
- Environment Variables setzen
- Port: 80
- Post-Deployment Command für Permissions + Cache Flush
Die Environment Variables sind dabei der wichtigste Teil. Sie definieren Context und DB-Zugang. Beispiel aus dem README:
TYPO3_CONTEXT=Production
TYPO3_DB_HOST=<mariadb-service>
TYPO3_DB_PORT=3306
TYPO3_DB_NAME=typo3db
TYPO3_DB_USERNAME=typo3user
TYPO3_DB_PASSWORD=<secret>
IS_DOCKER_ENV=trueCaveat: TYPO3_DB_HOST ist in Coolify typischerweise der Service-Name deines MariaDB-Containers (nicht „localhost“). Wenn TYPO3 keine DB-Verbindung bekommt, prüfe zuerst: Service-Name, Netzwerk/Compose-Setup in Coolify, Credentials, Port.
Der Post-Deployment Command aus dem README sorgt für korrekte Schreibrechte im var/-Verzeichnis und leert den TYPO3-Cache:
chown -R www-data:www-data /var/www/html/var
php /var/www/html/vendor/bin/typo3 cache:flush
Caveat: Permissions sind in Container-Deployments ein Klassiker. Wenn du Logs wie „Permission denied“ im var/ siehst, ist dieser Schritt essenziell. Je nach Base-Image/UID-Konzept kann es aber sein, dass du statt www-data einen anderen User brauchst. Halte dich zunächst ans README und passe nur an, wenn deine Container-User abweichen.
8) CI/CD mit GitHub Actions: Was passiert wann?
Die Workflows sind im Repo unter .github/workflows/ abgelegt: ci.yml und release.yml. Laut README umfasst CI bei jedem Push/PR:
- Code Quality: Composer validate, Dependency Checks
- PHP-CS-Fixer: Style nach PSR-12
- PHPStan: statische Analyse
- Security: Composer Audit
- Docker Build: Test-Build des Images
Continuous Deployment: Push auf main triggert Auto-Deploy zu Coolify via Webhook. Releases: Git Tag v* baut und publiziert ein Docker Image nach ghcr.io und erstellt ein GitHub Release.
Caveat: Webhook-Deployments sind robust, aber nicht „magisch“. Wenn ein Deploy nicht anläuft, prüfe in dieser Reihenfolge: (1) GitHub Actions Run (grün/rot), (2) ob der Webhook in Coolify korrekt hinterlegt ist, (3) ob Coolify den Build-Log zeigt und ob Env Vars vollständig sind. Häufigster Fehler in der Praxis: fehlende Secrets/Env Vars oder ein nicht erreichbarer DB-Service.
9) Code Quality & Security: Wie du es im Alltag nutzt
Der Mehrwert der Checks entsteht, wenn du sie als „Definition of Done“ behandelst: Ein PR ist erst fertig, wenn PHP-CS-Fixer und PHPStan sauber sind und Composer Audit keine kritischen Findings meldet. Gerade bei TYPO3-Projekten mit Extensions und wechselnden Dependencies verhindert das schleichende Qualitätsverluste.
Realistische Caveats:
- PHPStan kann bei TYPO3-spezifischen Patterns anfangs „zu streng“ wirken. Plane Zeit ein, Baselines oder gezielte Typ-Hints sauber nachzuziehen, statt die Analyse komplett zu entschärfen.
- PHP-CS-Fixer sollte im Team einheitlich laufen (idealerweise pre-commit oder per Editor-Integration). Sonst entstehen unnötige Diff-Konflikte.
- Security Audits (Composer Audit) liefern manchmal Findings in transitive Dependencies. Dann musst du abwägen: Update, Constraint anpassen oder (wenn möglich) ein Fix-Release abwarten. Wichtig ist, dass Findings sichtbar sind und nicht ignoriert werden.
10) Backup & Rollback: Docker Image Snapshots richtig einsetzen
Das Repo setzt auf Image-Snapshots pro Release. Das ist in der Praxis deutlich zuverlässiger als „Rollback per Git commit“, weil du exakt das getestete Artefakt wiederherstellst. Laut README kannst du ein Release-Image ziehen und in Coolify als Image-Quelle setzen.
docker pull ghcr.io/alandolsi/typo3-starter:v1.0.0Caveat: Ein Image-Rollback rollt nur den Code/Container-Stand zurück, nicht automatisch die Datenbank. Wenn du DB-Migrationen/Schema-Änderungen ausgerollt hast, brauchst du eine passende DB-Strategie (Backups, Migrations-Rollback, oder „forward fix“). Plane Releases so, dass DB-Änderungen kontrolliert und reversibel sind.
11) Cloudflare R2 im Kontext dieses Starters (S3-kompatibel, ohne CLI-Abhängigkeit)
Der Starter selbst implementiert keine R2-Anbindung, aber er ist dafür gut geeignet, weil er Konfiguration über Environment Variables und stateless Container priorisiert. Typische Einsatzfälle für Cloudflare R2 in TYPO3 sind: Auslagerung von Assets/Uploads oder Build-Artefakten in ein S3-kompatibles Object Storage.
Praktische Leitlinie: Halte R2-Zugangsdaten ausschließlich in Coolify/GitHub Secrets (nicht im Repo) und injiziere sie als Env Vars. Wenn du Dateien zwischen Umgebungen synchronisieren willst, nutze Tools, die S3-kompatible Endpoints unterstützen (z.B. rclone oder s3cmd) und konfiguriere den R2-Endpoint explizit. Beispiel-Endpoint-Form: https://<accountid>.r2.cloudflarestorage.com (Account-ID und Bucket-Konzept kommen aus deinem Cloudflare Dashboard). Achte darauf, dass du in DDEV/CI nicht versehentlich Production-Buckets beschreibst.
12) Empfohlener Ablauf für dein erstes echtes Projekt
- Schritt 1: Repo klonen, ddev start, Backend öffnen, Basis-Setup prüfen.
- Schritt 2: Site Package (packages/site_package) an Branding/Projekt anpassen.
- Schritt 3: Konfiguration strikt env-basiert halten (keine Secrets im Code).
- Schritt 4: Coolify App anlegen, Dockerfile-Build, Env Vars setzen, DB-Service anbinden.
- Schritt 5: Post-Deploy Command aktivieren (Permissions + Cache Flush).
- Schritt 6: CI-Checks ernst nehmen: Fixes im PR, nicht „nach dem Merge“.
- Schritt 7: Release über Git Tag v* erstellen, Image-Snapshot testen, Rollback-Prozess einmal trocken üben.
- Schritt 8: Optional: Cloudflare R2 als S3-kompatibles Storage ergänzen (Uploads/Assets), sauber über Env Vars und getrennte Buckets pro Umgebung.
Wenn du diesen Ablauf einhältst, bekommst du ein TYPO3-Setup, das lokal schnell startklar ist, in Production reproduzierbar deployt, und bei Problemen eine klare Debug-/Rollback-Story bietet. Genau diese Kombination ist der Kern des Repos: weniger „Server-Basteln“, mehr kontrollierbarer Software-Lifecycle.