- Laravel Deployment Workflow: Dev, Staging und Produktion richtig aufsetzen - 27. Oktober 2025
- Playwright MCP Server: Wie man der KI das Debuggen und Testen beibringt - 11. September 2025
- GitLab CI/CD zu langsam? So beschleunigen sie ihre Pipeline mit Caching! - 21. Juli 2025
Warum ein dreistufiger Laravel-Workflow unverzichtbar ist
Sie möchten Features schnell ausliefern, ohne Produktionsausfälle zu riskieren. Ein klar strukturierter Laravel Deployment Workflow mit dedizierten Dev-, Staging- und Produktions-Umgebungen schafft genau das: reproduzierbare Builds, kontrollierte Releases, sichere Datenflüsse und kurze Feedback-Zyklen. Dieser Leitfaden richtet sich an erfahrene Teams und zeigt einen durchgängigen Ansatz – von DNS über Webserver, Secrets und Datenabgleich bis hin zu CI/CD, Caching, Queues und Monitoring.
Zielbild: Entwickeln Sie lokal, integrieren Sie früh auf einem gemeinsamen Dev-Server, testen Sie realitätsnah auf Staging (mit produktionsnaher Konfiguration und Daten), deployen Sie kontrolliert in Produktion. Das reduziert Risiken, erhöht Transparenz und beschleunigt die Time-to-Value.
Klare Domänen und DNS: dev, staging, prod
Trennen Sie Umgebungen auf Ebene der Hostnamen. Bewährt haben sich:
- dev.example.com – gemeinsame Entwicklerinstanz
- staging.example.com – Testinstanz mit produktionsnaher Konfiguration und (anonymisierten) Produktivdaten
- example.com – Produktion
Technische Eckpunkte:
- Legen Sie pro Subdomain einen A-Record an (oder CNAME, falls ein Upstream-Proxy/Varnish/LB vorgeschaltet ist). Eine moderate TTL (z. B. 300–600 Sekunden) erleichtert Umstellungen.
- Planen Sie TLS für alle Umgebungen ein. Selbst Dev/Stage sind oft öffentlich erreichbar (z. B. für verteilte Teams), daher gehört HTTPS überall dazu.
- Schützen Sie nicht-öffentliche Umgebungen zusätzlich (siehe Abschnitt „Zugriffsschutz und Indexierungsstopp“).
Webserver-Setup mit TLS und HTTP/2
Laravel läuft sauber hinter Apache oder Nginx. Entscheidend ist eine saubere Trennung der DocumentRoots pro Umgebung (jeweils auf /public zeigen) und identische PHP-FPM-Stacks.
Beispiel Apache VirtualHost (2.4)
<VirtualHost *:80>
    ServerName dev.example.com
    DocumentRoot /var/www/yourproject/development/public
    <Directory /var/www/yourproject/development/public>
        AllowOverride All
        Require all granted
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/dev_error.log
    CustomLog ${APACHE_LOG_DIR}/dev_access.log combined
</VirtualHost>Für Staging analog, mit eigenem DocumentRoot. Aktivieren Sie die Sites mit a2ensite, laden Sie Apache neu. Anschließend Zertifikate per Let’s Encrypt/Certbot ausstellen (Apache- oder Nginx-Plugin verwenden) und Port 443 aktivieren.
HTTP/2 erhöht die Auslieferungseffizienz für statische Assets und APIs. Wenn Sie wissen möchten, wie Sie HTTP/2 am Webserver aktivieren, hilft unser Beitrag HTTP/2 Protokoll aktivieren beim Feintuning.
Hinweise:
- Setzen Sie identische PHP-Versionen und -Extensions über alle Umgebungen hinweg, um „Works on my machine“-Effekte zu vermeiden.
- Aktivieren Sie PHP OPcache in Staging/Prod.
- Achten Sie auf sichere Standard-Header (HSTS in Prod, restriktive CORS- und CSP-Policies nach Bedarf).
Zugriffsschutz und Indexierungsstopp in Dev/Staging
Nicht-Produktionsumgebungen gehören weder in Suchmaschinen noch in die Hände Dritter. Bewährte Maßnahmen:
- Basic Auth auf Webserverebene (Apache):
<Location "/">
    AuthType Basic
    AuthName "Restricted"
    AuthUserFile /etc/apache2/htpasswd-dev
    Require valid-user
</Location>- Alternativ/ergänzend IP-Whitelisting (z. B. via „Require ip“ in Apache oder Nginx allow/deny).
- „Disallow: /“ in robots.txt und idealerweise „X-Robots-Tag: noindex“ Header für Dev/Staging.
- In Laravel Staging: MAIL_MAILER=log oder Anbindung an ein dediziertes Test-Mail-System (MailHog). Keine externen produktiven Integrationen triggern.
Laravel-Projektstruktur pro Umgebung
Trennen Sie Deploy-Ziele sauber:
- /var/www/yourproject/development
- /var/www/yourproject/staging
- /var/www/yourproject/production (falls Sie nicht release-basierte Deployments verwenden)
Minimaler Deploy-Flow pro Zielverzeichnis:
# Erstdeployment (vereinfacht)
git clone git@repo.example.com:org/yourproject.git /var/www/yourproject/development
cd /var/www/yourproject/development
composer install --no-dev --optimize-autoloader
cp .env.example .env
php artisan key:generate
php artisan storage:link
# Rechte anpassen (siehe unten)Wichtige .env-Parameter pro Umgebung:
- APP_ENV=local (Dev), APP_ENV=staging (Staging), APP_ENV=production (Prod)
- APP_DEBUG=true nur in Dev; false in Staging/Prod
- APP_URL passend zur Domain (wichtig für URL-Generierung, Storage-URLs, Signierte URLs)
- DB_*, CACHE_DRIVER, QUEUE_CONNECTION, SESSION_DRIVER, LOG_CHANNEL, LOG_LEVEL
- MAIL_*, BROADCAST_DRIVER, FALLBACK_LOCALE
Prüfen Sie, dass Sie keine Closures in routes/web.php für Production verwenden, wenn Sie route:cache nutzen möchten.
Berechtigungen sicher setzen
Der Webserver-Benutzer (z. B. www-data) benötigt Schreibrechte auf storage/ und bootstrap/cache/. Arbeiten Sie mit einem dedizierten „deploy“-User und gemeinsamen Gruppenrechten, anstatt 0777 zu verwenden.
Beispiel (ohne ACL, mit Gruppenrechten):
# Gruppe setzen und Eigentümer sinnvoll vergeben
sudo chgrp -R www-data storage bootstrap/cache
sudo chown -R deploy:www-data storage bootstrap/cache
# Verzeichnisse 775, Dateien 664
find storage bootstrap/cache -type d -exec chmod 2775 {} +
find storage bootstrap/cache -type f -exec chmod 0664 {} +
# Erklärung:
# - 2 im Modus 2775 setzt das setgid-Bit, damit neue Einträge die Gruppen-ID erben
# - 775/664 erlaubt Schreibrechte für Owner und Gruppe, aber nicht für „others“Damit neue Dateien weiterhin gruppen-schreibbar angelegt werden, sollte die umgebende Prozess-Umask 0002 sein. Für Deploy-Skripte setzen Sie umask 0002. Für PHP-FPM können Sie dies über eine systemd-Override-Datei sicherstellen:
sudo systemctl edit php8.2-fpm.service
# Editor öffnet sich, einfügen:
[Service]
UMask=0002
sudo systemctl daemon-reload
sudo systemctl restart php8.2-fpmDiese Variante hält Rechte restriktiv und vermeidet 0777. Weitere Hintergründe und Alternativen haben wir in Laravel Storage Folder Berechtigungen richtig setzen erläutert.
Datenbank: Migrations, Seeds und Versionsstand
- Führen Sie Schemaänderungen ausschließlich via „php artisan migrate –force“ im Deploy-Prozess aus.
- Seed-Daten für lokale Entwicklung separat halten (z. B. Dummy-User, Feature-Toggles). In Staging können Seeds für synthetische Testdaten sinnvoll sein – idealerweise nach dem Import anonymisierter Produktionsdaten.
- Vermeiden Sie manuelle Änderungen am Schema in Prod. Jede Änderung gehört in eine Migration.
Arbeitsschritte im Deploy:
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cacheHinweis: route:cache setzt voraus, dass keine Route-Closures verwendet werden. Nutzen Sie Controller-Methoden.
Staging auf Produktionsstand halten: DB- und Filesync mit Sanitization
Eine Staging-Instanz ist nur dann aussagekräftig, wenn Daten und Dateien den Produktionszustand widerspiegeln – ohne echte personenbezogene Daten preiszugeben.
Sichere Datenübernahme aus Produktion
- Dump aus Prod für InnoDB ohne Locking:
mysqldump \
  --single-transaction --quick --routines --events --triggers \
  -u "$PROD_DB_USER" -p \
  "$PROD_DB_NAME" | gzip > /tmp/prod.sql.gzHinterlegen Sie Credentials bevorzugt in einer geschützten Client-Config (z. B. ~/.my.cnf) oder via „–defaults-extra-file“, statt Passwörter auf der Kommandozeile zu übergeben.
- Transfer per SSH:
scp /tmp/prod.sql.gz staging-user@staging.example.com:/tmp/- Optional: Vor dem Import Staging-DB sichern und dann ersetzen:
ssh staging-user@staging.example.com \
  "mysqldump -u '$STG_DB_USER' -p '$STG_DB_NAME' | gzip > /tmp/staging_backup_$(date +%F_%H%M).sql.gz && \
   mysql -u '$STG_DB_USER' -p -e \"DROP DATABASE IF EXISTS $STG_DB_NAME; CREATE DATABASE $STG_DB_NAME;\" && \
   gunzip -c /tmp/prod.sql.gz | mysql -u '$STG_DB_USER' -p '$STG_DB_NAME' && \
   rm /tmp/prod.sql.gz"Anonymisierung sensibler Daten
Behandeln Sie PII in Staging grundsätzlich als „nicht erlaubt“. Anonymisieren Sie E-Mail-Adressen, Telefonnummern, Namen und Freitextfelder. Zwei praktikable Wege:
- Nachgelagerte SQL-Updates, z. B.:
UPDATE users 
SET email = CONCAT('user+', id, '@example.invalid'),
    name = CONCAT('User ', id),
    phone = NULL,
    remember_token = NULL;- Anonymisierung via Laravel-Command, das direkt nach dem Import ausgeführt wird. Vorteil: Sie können komplexe Regeln kapseln (RegEx, konsistente Pseudonymisierung, referentielle Integrität).
Wichtig: Unterbinden Sie aus Staging heraus jegliche produktive Kommunikation (E-Mail, Payment, Drittsysteme). Setzen Sie MAIL_MAILER=log und deaktivieren/isolieren Sie API-Keys.
Dateisynchronisation (Storage)
Wenn Benutzer Dateien hochladen (storage/app/public oder ein S3-Bucket), stimmen DB-Referenzen ohne Dateisync nicht. Für lokale/Server-Storage synchronisieren Sie per rsync:
rsync -a --delete -e ssh \
  /var/www/yourproject/production/storage/app/public/ \
  staging-user@staging.example.com:/var/www/yourproject/staging/storage/app/public/Achtung bei „–delete“: Es entfernt Dateien auf Staging, die nicht in Prod vorhanden sind. Nutzen Sie ggf. eine Exclude-Liste für Testdaten.
Planen Sie DB- und File-Sync nachts via Cron in Prod, informieren Sie Stakeholder über das Wartungsfenster auf Staging.
Git-Strategie: Trunk-basiert oder klassisches Dev/Staging/Main
Für Teams mit klaren Qualitätsstufen bewährt sich:
- development: Integrations-Branch aus Feature-Branches
- staging: stabilisierte Changes für Release-Kandidaten
- main: produktiver Stand
Feature-Branches gehen per Merge Request in development; nach erfolgreichem Test in staging; Release-Freigabe führt den Merge nach main aus. Halten Sie Rebases/merges transparent, schützen Sie main/staging mit Reviews. Konventionelle Commits bleiben hilfreich (feat:, fix:, refactor:), auch für automatische Changelogs.
Wenn Sie GitLab einsetzen, lohnt ein Blick auf unseren Beitrag Effiziente Deployments mit GitLab Runner und CI/CD, in dem wir praxisnahe Pipeline-Muster und Runner-Konfigurationen zeigen.
CI/CD-Pipelines: Build, Test, Deploy – deterministisch und sicher
Automatisieren Sie alle Umgebungsschritte. Beispiel GitLab CI (.gitlab-ci.yml) mit Deploy auf Dev/Staging/Prod via SSH:
stages: [build, test, deploy]
variables:
  GIT_DEPTH: 1
  COMPOSER_INSTALL_FLAGS: "--no-ansi --no-interaction --prefer-dist --no-progress --no-suggest"
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - vendor/
    - node_modules/
build_app:
  stage: build
  image: php:8.2-cli
  services: []
  script:
    - apt-get update && apt-get install -y git unzip libzip-dev
    - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
    - composer install ${COMPOSER_INSTALL_FLAGS}
    - php artisan vendor:publish --force --all || true
    - php -v
  artifacts:
    paths:
      - vendor/
    expire_in: 1h
build_assets:
  stage: build
  image: node:20-alpine
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - public/build
    expire_in: 1h
unit_tests:
  stage: test
  image: php:8.2-cli
  script:
    - vendor/bin/phpunit --colors=never --testdox
.deploy_template: &deploy_template
  stage: deploy
  image: alpine:3.19
  before_script:
    - apk add --no-cache openssh-client rsync bash
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - 2>/dev/null || true
    - ssh-keyscan -H $TARGET_HOST >> ~/.ssh/known_hosts
  script:
    - >
      ssh $TARGET_USER@$TARGET_HOST \
      "cd $TARGET_PATH && \
       git fetch origin $CI_COMMIT_REF_NAME && git checkout $CI_COMMIT_SHA && \
       composer install --no-dev --optimize-autoloader && \
       php artisan down && \
       php artisan migrate --force && \
       php artisan config:cache && php artisan route:cache && php artisan view:cache && \
       php artisan up"
deploy_dev:
  <<: *deploy_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "development"'
deploy_staging:
  <<: *deploy_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "staging"'
deploy_prod:
  <<: *deploy_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual
      allow_failure: falseEckpunkte:
- Secrets (SSH_PRIVATE_KEY, DB- und API-Keys) gehören in CI-Secret-Stores, nicht ins Repo.
- Bauen Sie Assets deterministisch („npm ci“, nicht „npm install“), prüfen Sie, dass Vite-Builds in Prod korrekt referenziert werden.
- Wählen Sie je nach Tooling ein Zero-Downtime-Verfahren (Releases mit Symlinks, Blue/Green oder Canary). Das obige Beispiel zeigt einen direkten Ansatz mit Maintenance-Mode.
Wenn Sie GitLab als zentrales System aufsetzen oder modernisieren möchten, unterstützen wir Sie auch als Dienstleister. Informationen finden Sie auf unserer Seite zu GitLab CE.
Caching, Sessions und Performance in Prod
- Konfigurieren Sie Redis als Cache-, Session- und Queue-Backend für Staging/Prod. Das reduziert Latenz und entlastet die DB.
- Nutzen Sie „php artisan config:cache“, „route:cache“ und „view:cache“ im Deploy, um Bootstrapping zu beschleunigen. Leeren Sie die Caches nur gezielt.
- Aktivieren Sie OPcache mit sinnvollen Einstellungen (z. B. ausreichend großem Memory-Buffer, JIT optional, je nach Workload). Halten Sie CLI/ FPM auf gleicher PHP-Version.
Queues zuverlässig betreiben
Hintergrundjobs entkoppeln Latenzen. In Dev reicht „sync“ oder „database“; in Staging/Prod nutzen Sie „redis“ oder „sqs“. Starten Sie Worker unter Aufsicht von systemd oder Supervisor.
Supervisor für Laravel-Queues im Detail
Supervisor überwacht Prozesse und startet sie bei Fehlern neu. So setzen Sie robuste Worker-Gruppen auf:
Installation (Debian/Ubuntu):
sudo apt-get update && sudo apt-get install -y supervisorBeispielkonfiguration für mehrere Worker und Warteschlangen priorisiert nach „high,default,low“:
# /etc/supervisor/conf.d/laravel-queue.conf
[program:laravel-worker-default]
process_name=%(program_name)s_%(process_num)02d
command=/usr/bin/php /var/www/yourproject/production/artisan queue:work redis --queue=default --sleep=3 --tries=3 --max-jobs=500 --max-time=3600 --memory=256
numprocs=3
user=www-data
directory=/var/www/yourproject/production
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stopsignal=TERM
stopwaitsecs=3600
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-worker-default.log
stdout_logfile_maxbytes=20MB
stdout_logfile_backups=5
[program:laravel-worker-high]
process_name=%(program_name)s_%(process_num)02d
command=/usr/bin/php /var/www/yourproject/production/artisan queue:work redis --queue=high,default --sleep=1 --tries=5 --max-jobs=500 --max-time=3600 --memory=256
numprocs=2
user=www-data
directory=/var/www/yourproject/production
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stopsignal=TERM
stopwaitsecs=3600
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-worker-high.log
stdout_logfile_maxbytes=20MB
stdout_logfile_backups=5
[group:laravel-workers]
programs=laravel-worker-high,laravel-worker-defaultAktivieren und prüfen:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl statusBewährte Hinweise:
- Nutzen Sie php artisan queue:restartfür einen rollierenden, sicheren Neustart der Worker nach Deployments. Supervisor erkennt Exit-Codes und startet die Prozesse neu.
- Setzen Sie --max-jobsoder--max-time, damit Worker regelmäßig neu starten und Speicher leeren. Das beugt Leaks und Treiber-Drift vor.
- Trennen Sie Warteschlangen nach Priorität (--queue=high,default,low) und weisen Sie pro Queue eigene Program-Blöcke/Prozesszahlen zu.
- Logfiles rotieren (siehe stdout_logfile_*). Für zentrale Logs: Ausgabe an syslog leiten oder einen Log-Forwarder nutzen.
- Für lange Jobs erhöhen Sie stopwaitsecs, damit Worker Jobs sauber beenden, bevor Supervisor sie beendet.
Alternative: systemd-Service für einen Worker
Wenn Sie Supervisor nicht einsetzen möchten, funktioniert ein systemd-Service stabil für einfache Setups:
[Unit]
Description=Laravel Queue Worker
After=network.target
[Service]
User=www-data
Group=www-data
Restart=always
ExecStart=/usr/bin/php /var/www/yourproject/production/artisan queue:work --sleep=3 --tries=3 --max-time=3600
WorkingDirectory=/var/www/yourproject/production
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=laravel-queue
KillSignal=SIGTERM
TimeoutStopSec=3600
[Install]
WantedBy=multi-user.targetAktivieren mit:
sudo systemctl daemon-reload
sudo systemctl enable --now laravel-queue.serviceEine kompakte Einführung in Architektur und Best Practices finden Sie in unserem Beitrag Jobs und Warteschlangen in Laravel.
Scheduler sauber ausführen
Planen Sie cron auf dem Server so, dass der Laravel-Scheduler minütlich ausgeführt wird. Alle zeitgesteuerten Aufgaben gehören in app/Console/Kernel.php.
# /etc/crontab oder crontab -e
* * * * * www-data /usr/bin/php /var/www/yourproject/production/artisan schedule:run >> /dev/null 2>&1Mehr zu Konfiguration, Debugging und typischen Stolperfallen erläutern wir im Artikel Laravel Scheduler.
E-Mail, Broadcasting, externe Integrationen
- Staging: MAIL_MAILER=log oder ein dedizierter Test-Mailserver. Verhindern Sie E-Mails an echte Nutzer.
- Broadcasting: Nutzen Sie in Prod einen skalierbaren Treiber (Redis, pusher-kompatible Services) und in Staging eine isolierte Konfiguration.
- Externe APIs: Verwenden Sie Sandbox-Keys in Staging, Mock-Services in Dev. Trennen Sie Secrets strikt per Umgebung.
Logging und Monitoring
- Laravel-Logs auf „daily“ rotieren, Log-Level je Umgebung setzen (Dev: debug, Staging/Prod: info/warning/error je nach Bedarf).
- Zentralisieren Sie Logs (rsyslog/journald-Forwarding, ELK/ OpenSearch, o. ä.).
- Technische Metriken: CPU, RAM, Disk, Netz, FPM-Worker-Auslastung, Queue-Backlog, Apdex/Response-Zeiten. Alerts für Anomalien einrichten.
- Health-Checks der Applikation (z. B. /healthz) in Ihr Monitoring integrieren.
Sicherheitshärtung über alle Ebenen
- SSH nur per Key, Passwortauthentifizierung deaktivieren; Fail2Ban/Rate-Limits.
- Firewall strikt: 22, 80, 443 – DB-Ports nur intern/VPN.
- Pro Umgebung getrennte DB-User mit minimalen Rechten.
- Paket- und PHP-Sicherheitsupdates regelmäßig einspielen; Composer-Abhängigkeiten aktuell halten.
- .env-Dateien niemals ins Repo commiten. Zugriffssystematik dokumentieren, Secrets rotieren.
- Für Dev/Staging: BasicAuth/IP-Restriktion und Noindex (siehe oben). Für Prod: HSTS, korrekte TLS-Konfiguration, CSP nach Bedarf.
Asset-Builds mit Vite reproduzierbar machen
- Setzen Sie in CI „npm ci“ ein, nicht „npm install“; definieren Sie Node-Versionen (z. B. via .nvmrc oder CI-Image).
- Prüfen Sie, dass @vite() in Blade-Templates in Prod auf gebaute Assets verweist (mix/Vite-Manifest korrekt ausgeliefert). Cachen Sie public/build effizient via Webserver-Konfiguration.
Rollback-Strategien realistisch planen
- Vor jedem produktiven Deploy: DB-Snapshot/Backup erstellen. Schemarollbacks sind riskant, wenn Datenmigrationen irreversible Schritte enthalten.
- Release-Verzeichnisse mit Symlink-Switch ermöglichen schnelle Rücksprünge auf die letzte Version, ohne Dateien erneut zu kopieren.
- Feature-Flags erlauben schrittweise Aktivierung; in Staging aktivieren, in Prod nach Metrik-Validierung freischalten.
Containerisierung als Option für Parität
Mit Docker/Compose oder Kubernetes erreichen Sie identische Laufzeitumgebungen für Dev/Staging/Prod. Trennen Sie Services (PHP-FPM, Nginx, Redis, DB) in dedizierte Container, verwenden Sie Multi-Stage-Builds und definieren Sie Umgebungskonfigurationen über Compose-Overlays oder Helm. Für Teams, die ohne Container starten, sollte mindestens die Prod/Stage-Umgebung in Paketen und Versionen klar dokumentiert sein, um schnell reproduzierbar zu bleiben.
Praxisnahe Checkliste für Ihren Laravel Deployment Workflow
- DNS und TLS: Subdomains eingerichtet, Zertifikate ausgestellt, HTTP/2 aktiv
- Webserver: Getrennte vhosts, identische PHP-FPM-Konfiguration, OPcache aktiv
- Zugriffsschutz: BasicAuth/Whitelist auf Dev/Staging, Noindex, Mails geblockt
- Projektstruktur: Saubere Verzeichnisse pro Umgebung, Storage-Symlink, Rechte korrekt
- Env-Variablen: APP_ENV/APP_URL/DEBUG, DB/Cache/Queue/Mail/Broadcast je Umgebung
- Deploy-Schritte: git fetch/checkout, composer install, npm build, artisan down/migrate/cache/up
- Datenflüsse: Nacht-Job für anonymisierte DB- und File-Sync von Prod → Staging
- CI/CD: Pipeline mit Build/Test/Deploy, Secrets im Vault, manuelles Gate für Prod
- Queues & Scheduler: Supervisor oder systemd für Worker, Cron für schedule:run
- Logging & Monitoring: Zentrale Logs, Metriken, Health-Checks, Alerts
- Sicherheit: SSH-Keys, Firewall, minimale DB-Rechte, Updates, Secret-Management
- Rollback: DB-Backups, Release-Symlinks, Feature-Flags
Häufige Stolperfallen – und wie Sie sie vermeiden
- Route-Closures blockieren route:cache → auf Controller-Methoden umstellen.
- Fehlende Berechtigungen auf storage/ führen zu 500-Errors → Rechte sauber setzen (siehe oben).
- Staging sendet E-Mails an echte Nutzer → MAIL_MAILER=log und Dummy-Domains nutzen.
- Unterschiedliche PHP- oder Extension-Stände in Dev/Prod → Versionsparität sicherstellen.
- Lange CI-Laufzeiten durch fehlendes Caching → Composer- und Node-Caches einsetzen; Runner-Sizing prüfen. Mehr dazu im verlinkten Beitrag zu GitLab Runner und CI/CD.
Ein vollständiger Beispiel-Workflow Ende-zu-Ende
Angenommen, Sie mergen eine Feature-Branch in „development“:
- GitLab CI baut Composer- und Vite-Artefakte, führt Unit- und Integrationstests aus.
- deploy_dev-Job deployed automatisiert nach dev.example.com: git checkout, composer install, migrations, caches, FPM reload.
- QA meldet Abnahme, Merge nach „staging“ triggert Staging-Deploy. Zusätzlich laufen E2E-Tests gegen staging.example.com.
- Ein nächtlicher Job importiert anonymisierte Prod-Daten in Staging und synchronisiert Files – Staging bleibt realitätsnah.
- Nach Freigabe mergen Sie nach „main“. Ein manueller Gate im CI startet deploy_prod. Vor dem Switch erzeugt das System ein DB-Backup, setzt die App in Maintenance-Mode, migriert, cached und reaktiviert.
- Monitoring behält Metriken und Logs im Blick. Bei Problemen steht das vorige Release per Symlink-Rollback bereit.
Mit diesem Setup erreichen Sie stabile Releases, schnelle Iterationen und nachvollziehbare Audits – ohne Überraschungen im Livebetrieb.
Übrigens: Wenn Sie zusätzlich Ihre Pipeline-Performance optimieren möchten, lohnt ergänzend ein Blick auf unseren Beitrag Effiziente Deployments mit GitLab Runner und CI/CD. Und für HTTP-Optimierung auf Protokollebene zeigt HTTP/2 Protokoll aktivieren, welche Stellschrauben am Webserver sinnvoll sind.
Benötigen Sie weitere praxistaugliche Laravel-Muster? Stöbern Sie in unserer Kategorie Laravel oder vertiefen Sie Einzelthemen wie Jobs und Warteschlangen in Laravel und Laravel Scheduler. Wenn Sie bei der Umsetzung Ihres Deployment-Workflows Unterstützung wünschen, sprechen Sie uns gerne an – der Einstieg über unser Blog auf https://blog.admin-code.de/ ist ein guter erster Schritt, oder kontaktieren Sie uns direkt über unser Kontaktformular.
 
			