Skip to content

Staging-Deploy für die Kunden-Demo ​

Legacy / historisch (Stand 2026-05)

Kanonischer Deploy-Weg ist jetzt Deployment (Deployer deploy.php + Woodpecker). Es gibt keinen separaten Staging-Server — alles läuft auf 172.16.111.40 (SSH-Alias matev-deploy); staging.matev.eu ist nur der Proxy. Dieses Dokument bleibt als historischer Demo-Pfad.

Der schnelle Demo-Pfad ohne Woodpecker — wenn die CI noch nicht steht oder ein Image lokal frisch gebaut werden muss.

Hintergrund: Forgejo-Domain git.matev.eu ist aktuell nicht durchgehend erreichbar. Die Service-Submodules (admin/, shared/) liegen lokal in der Infrastruktur. Bis Forgejo + Registry stabil sind, bauen wir Images lokal und pushen sie per docker save + scp auf den Staging-Server (oder direkt in eine erreichbare Registry).

Reihenfolge für die Demo ​

  1. admin (Filament-PIM) — Kunde sieht das Backend
  2. cms (Kirby) + staging (Nuxt) — Kunde sieht Marketing-Frontend mit echtem CMS-Inhalt
  3. storybook — Kunde sieht die CMS-Komponenten isoliert
  4. (später) b2b (Livewire) — Händlerportal

Voraussetzungen auf dem Staging-Server (einmalig) ​

bash
ssh root@staging.matev.eu

# Docker
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker

# Deploy-User
adduser --disabled-password --gecos "" bengel
usermod -aG docker bengel
mkdir -p /home/bengel/.ssh
echo '<DEIN_SSH_PUB_KEY>' >> /home/bengel/.ssh/authorized_keys
chown -R bengel:bengel /home/bengel/.ssh && chmod 700 /home/bengel/.ssh

# Firewall
ufw allow 22,80,443/tcp && ufw allow 443/udp && ufw enable

# Externes Docker-Netz für alle Stacks
docker network create gateway

# Stack-Repo holen (oder per scp übertragen, solange Forgejo down)
mkdir -p /home/bengel/stacks
cd /home/bengel/stacks
git clone https://git.matev.eu/matev/server-stacks.git .
# Notfall: scp -r dev-laptop:/path/to/stacks/* bengel@staging.matev.eu:~/stacks/

chown -R bengel:bengel /home/bengel/stacks

.env-Dateien händisch anlegen — Werte aus dem Passwort-Manager (1Password / Bitwarden):

bash
nano /home/bengel/stacks/proxy/.env       # ggf. leer
nano /home/bengel/stacks/mgmt/.env
nano /home/bengel/stacks/git/.env
nano /home/bengel/stacks/apps/.env

(Inhalt siehe Stacks-Referenz.)

Stacks initial hochfahren ​

bash
ssh bengel@staging.matev.eu

cd ~/stacks/proxy && docker compose up -d         # Caddy zuerst
cd ~/stacks/mgmt  && docker compose up -d         # Portainer + Matomo
cd ~/stacks/git   && docker compose up -d         # Forgejo + Woodpecker (sobald nutzbar)
cd ~/stacks/apps  && docker compose up -d         # Apps zum Schluss

Caddy hat dann automatisch SSL-Zertifikate für alle Hosts gezogen, sobald DNS auf den Server zeigt.

Demo-Pfad A — Code per rsync, Build auf dem Server (empfohlen) ​

So passt das zur Server-Webroot-Konvention /var/www/<service>/. Der Build läuft direkt auf dem Server, kein Image-Transfer nötig.

bash
# 1) Code vom Dev-Rechner auf den Server (admin)
rsync -av --delete \
    --exclude='node_modules' --exclude='vendor' --exclude='.env' \
    --exclude='storage/app/public' --exclude='storage/logs' \
    /pfad/zu/matev_2026/admin/ \
    bengel@staging.matev.eu:/var/www/admin/

# 1b) Dockerfile aus den Referenzen übertragen (einmalig pro Service)
scp /pfad/zu/matev_2026/home/bengel/stacks/apps/dockerfiles-reference/admin.Dockerfile \
    bengel@staging.matev.eu:/var/www/admin/Dockerfile

# 2) Auf dem Server: .env eintragen + bauen + hochziehen
ssh bengel@staging.matev.eu << 'EOF'
# .env initial setzen (nur einmal)
[ -f /var/www/admin/.env ] || cp /var/www/admin/.env.example /var/www/admin/.env
nano /var/www/admin/.env       # APP_KEY, DB-Passwort, Mail, Search-Keys

cd ~/stacks/apps
docker compose build admin
docker compose up -d apps-db apps-redis admin

# Migrationen + Cache
docker compose exec admin php artisan migrate --force --graceful
docker compose exec admin php artisan db:seed --force
docker compose exec admin php artisan filament:optimize
docker compose exec admin php artisan octane:reload
EOF

Demo-Pfad B — Image lokal bauen + transferieren (Fallback ohne Forgejo-Registry) ​

Wenn der Server zu schwach für den Build ist oder kein direkter Code-Push möglich:

bash
# 1) Image lokal bauen — Build-Context lokal /pfad/zu/admin/
cd /pfad/zu/matev_2026/admin
cp ../home/bengel/stacks/apps/dockerfiles-reference/admin.Dockerfile Dockerfile
docker build -t matev/admin:demo .

# 2) Tarball + Transfer
docker save matev/admin:demo | gzip > /tmp/admin-demo.tar.gz
scp /tmp/admin-demo.tar.gz bengel@staging.matev.eu:/tmp/

# 3) Auf dem Server laden und in apps/docker-compose.yml `image: matev/admin:demo`
# eintragen statt build:, dann up -d admin
ssh bengel@staging.matev.eu "docker load < /tmp/admin-demo.tar.gz"

Pimcore-Daten in den Staging-Admin importieren ​

bash
# Lokalen Dump hochladen
scp migration/exports/pimcore-2026-04-27.sql.gz bengel@staging.matev.eu:/tmp/

# Auf den Staging-Server
ssh bengel@staging.matev.eu

# Dump in den apps-db-Container streamen — getrennte DB für Pimcore-Quelldaten
docker exec -i apps-db mariadb -u root -p"$APPS_DB_ROOT_PASSWORD" -e \
    "CREATE DATABASE IF NOT EXISTS matev_pimcore_source;"
gunzip -c /tmp/pimcore-2026-04-27.sql.gz | \
    docker exec -i apps-db mariadb -u root -p"$APPS_DB_ROOT_PASSWORD" matev_pimcore_source

# Importer im admin-Container laufen lassen
cd ~/stacks/apps
docker compose exec admin php artisan import:pimcore --dry-run
docker compose exec admin php artisan import:pimcore --phase=1   # Stammdaten
docker compose exec admin php artisan import:pimcore --phase=2   # Tractor + Dealer
docker compose exec admin php artisan import:pimcore --phase=3   # Articles + Bricks
docker compose exec admin php artisan import:pimcore --phase=4   # Offers + Orders
docker compose exec admin php artisan import:pimcore --phase=5   # Konfiguration

docker compose exec admin php artisan blueprints:generate

Storybook deployen (statisches Build) ​

Storybook ist ein statisches Build — kein PHP, kein Bun-Server zur Laufzeit nötig:

bash
# 1) Lokal bauen
cd storybook
bun install
bun run build-storybook                              # Output: storybook-static/

# 2) Auf den Server rsyncen — in den Webroot, der read-only ins
# storybook-Container gemountet wird:
rsync -av --delete storybook-static/ \
    bengel@staging.matev.eu:/var/www/storybook/

# 3) nginx im Container muss nicht neu starten — er liest live aus dem Mount

Caddy-Route ist storybook.matev.eu → storybook:80 (siehe apps/docker-compose.yml).

Kirby + Nuxt-Staging-Frontend ​

Empfohlen: Code-Push direkt nach /var/www/<service>/, dann Build auf dem Server (analog admin).

bash
# Kirby
rsync -av --delete --exclude='vendor' /pfad/zu/cms/ bengel@staging.matev.eu:/var/www/cms/
scp /pfad/zu/home/bengel/stacks/apps/dockerfiles-reference/cms.Dockerfile \
    bengel@staging.matev.eu:/var/www/cms/Dockerfile
ssh bengel@staging.matev.eu "mkdir -p /var/www/cms/.docker"
scp /pfad/zu/home/bengel/stacks/apps/dockerfiles-reference/cms.Caddyfile \
    bengel@staging.matev.eu:/var/www/cms/.docker/Caddyfile

ssh bengel@staging.matev.eu "cd ~/stacks/apps && docker compose build cms && docker compose up -d cms"

# Nuxt-Staging-Frontend
rsync -av --delete --exclude='node_modules' --exclude='.output' \
    /pfad/zu/staging/ bengel@staging.matev.eu:/var/www/staging/
scp /pfad/zu/home/bengel/stacks/apps/dockerfiles-reference/staging.Dockerfile \
    bengel@staging.matev.eu:/var/www/staging/Dockerfile

ssh bengel@staging.matev.eu "cd ~/stacks/apps && docker compose build staging && docker compose up -d staging"

Kirby-Content initial: rsync -av /pfad/zu/cms/content/ bengel@staging.matev.eu:/var/www/cms/content/.

Demo-Stand für den Kunden ​

URLInhaltLogin
https://admin.matev.eu/adminFilament PIM — Stammdaten, Artikel, Tractoren, Produkteadmin@matev.eu / admin
https://cms.matev.eu/panelKirby Panel — CMS-Inhalt redaktionell pflegeninitial setzen
https://staging.matev.euNuxt-Frontend — gerendertes CMS + Produkt-Listen—
https://storybook.matev.euKomponenten-Showroom — Spec-Bricks, Page-Layouts—

Kurz-Pitch für das Kundengespräch:

"Drei Bausteine sehen Sie heute live:

  1. Im Filament-PIM verwalten Sie alle Produktdaten — die Pimcore-Bestände sind über import:pimcore 1:1 übernehmbar (5.255 Hauptartikel, 524 Produkte, 362 Traktoren). Multi-Sprache (DE/EN/FR) ist Pflichtfeature, ebenso die 41 Spezifikations-Bricks.
  2. Im Kirby-CMS pflegen Ihre Redakteure die Marketing-Seiten — Bilder, Texte, Landingpages — mit Live-Vorschau im Panel. Über GraphQL wird der Inhalt vom Nuxt-Frontend in Realtime ausgespielt.
  3. Im Storybook sehen Sie alle CMS-Komponenten isoliert — jede ist aus einem YAML-Schema generiert (Single Source of Truth), das gleichzeitig Filament-Validierung und Frontend-Rendering speist.

Das Händlerportal (B2B-Bestellungen, Konfigurator) folgt im nächsten Sprint als Livewire-Anwendung — die Schnittstellen (REST + GraphQL) stehen bereits."

Rollback (Demo-Notfall) ​

bash
ssh bengel@staging.matev.eu
docker images matev/admin                              # Liste aller geladenen Tags
# Image-Tag in apps/docker-compose.yml auf älteren Tag setzen, dann:
cd ~/stacks/apps && docker compose up -d admin

Pre-Demo-Checkliste ​

  • [ ] DNS auf alle Demo-Hosts zeigt (admin, cms, staging, storybook): dig +short admin.matev.eu
  • [ ] Caddy hat alle Zertifikate gezogen: curl -I https://admin.matev.eu → HTTP/2 200
  • [ ] https://admin.matev.eu/admin lädt; Login admin@matev.eu / admin klappt
  • [ ] Mindestens 1 Maker, 1 MainArticle, 1 Tractor sichtbar (notfalls via Filament-UI anlegen)
  • [ ] https://cms.matev.eu/api/query antwortet auf einen KQL-POST ({"query":"site"}) bzw. GraphQL je nach Plugin
  • [ ] https://staging.matev.eu rendert Startseite mit echtem CMS-Inhalt (kein 502)
  • [ ] https://storybook.matev.eu lädt; alle Story-Gruppen (Spec, Area, Snippet, Page) ohne JS-Fehler
  • [ ] Pimcore-Phase-1-Import gelaufen (Stammdaten sichtbar)
  • [ ] Backup-Cron läuft (crontab -l zeigt db-backup.sh und matev-backup.sh)

Sobald Forgejo + Woodpecker stabil sind ​

Den docker save/docker load-Workflow ablösen durch:

  • Forgejo-Container-Registry aktivieren (Settings → Packages)
  • Woodpecker-Pipeline pushed Images automatisch (siehe Deployment)
  • apps/docker-compose.yml referenziert image: git.matev.eu/matev/admin:develop statt build:
  • Rollback per Image-Tag-Switch in apps/docker-compose.yml (Git-tracked!)