CI/CD für WordPress: automatisierte Deployments im Jahr 2026

CI/CD für WordPress: automatisierte Deployments im Jahr 2026

Zuletzt überprüft: 15. Oktober 2026
12 Min. Lesezeit
Leitfaden
Full-Stack-Entwickler

Themen per FTP hochzuziehen endet 2026 meist gleich: eine Datei aus inc/ fehlt, composer.lock stammt von einem anderen Laptop, und Produktion liegt, weil jemand wp-config.php überschrieben hat. Continuous Integration und Continuous Deployment sind keine Enterprise-Show - sie sorgen dafür, dass jede Git-Änderung denselben Build, dieselben Tests und denselben Weg auf den Server nimmt.

Dieser Leitfaden gilt für WordPress mit Theme oder Plugin im Repository (Composer, npm, optional Docker), nicht für Seiten, die nur im Admin leben. Liegt Custom-Code noch nur in Datenbank und Medienbibliothek, bring Themes und eigenen Code zuerst in Git - sonst hat CI/CD nichts zu bauen.

Runner-Dokumentation: GitHub Actions. Parallel lesenswert: Hardening WordPress. Für Befehle nach dem Deploy: WP-CLI.

#Warum WordPress per FTP deployen riskant ist

Drei Muster tauchen in Audits deutscher WooCommerce-Shops und Agentur-Übergaben immer wieder auf:

  1. Umgebungsdrift - lokal PHP 8.2 und Composer 2.7, auf dem Hetzner-VPS PHP 8.1 ohne intl. Lokal „läuft“ composer install, Produktion stirbt an class not found.
  2. Kein Audit-Trail - nach einem Vorfall ist unklar, welcher Commit live war. Das Hosting-Panel zeigt ein Dateidatum, keine Git-SHA.
  3. Secrets auf der Platte - SFTP-Passwörter in FileZilla oder eine „kurz“ committed .env bleiben der klassische Leak-Pfad - und bei DSGVO-Fällen teuer.

CI/CD löst das mechanisch: Build auf bekanntem Image (shivammathur/setup-php oder eigenes Docker), Artefakt versioniert nach SHA, Deploy per SSH-Key aus Secrets.

#WordPress mit GitHub Actions deployen

Typischer Workflow für Custom-Theme plus Composer-Plugins:

  1. Trigger - Push auf main oder Merge eines reviewed Pull Requests. develop geht oft nur auf Staging.
  2. Build - composer install --no-dev --optimize-autoloader, npm ci, npm run build. PHP und Node im Workflow pinnen (php-version: '8.3', node-version: '24').
  3. Test - PHPUnit für Plugins, optional Playwright auf dem Checkout. Fail = Stop, kein Deploy.
  4. Artefakt - Release ohne .git, ohne node_modules, mit vendor/ und gebautem assets/dist/.
  5. Deploy - rsync/SCP nach releases/<run_id>/, danach atomares Symlink-Umschalten.

Pinnen Sie Versionen, die noch Fixes bekommen. PHP 8.2 erhält Sicherheitsupdates nur bis 31. Dezember 2026, PHP 8.3 bis 31. Dezember 2027 (unterstützte PHP-Versionen). Node.js 20 hat am 30. April 2026 sein Lebensende erreicht; Node.js 22 wird bis 30. April 2027 unterstützt, Node.js 24 bis 30. April 2028 (Node.js-Release-Plan). Die PHP-Minor-Version richtet sich nach der Produktion, nicht nach dem neuesten Release.

Kurzskizze in GitHub Actions, mit Major-Tags zur besseren Lesbarkeit; warum produktive Workflows Commit-SHAs pinnen, erklärt der Abschnitt zur Härtung weiter unten:

name: deploy-production
on:
  push:
    branches: [main]
permissions:
  contents: read
concurrency:
  group: deploy-production
  cancel-in-progress: false
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v7
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
      - run: composer install --no-dev --optimize-autoloader
      - uses: actions/setup-node@v7
        with:
          node-version: '24'
          cache: npm
      - run: npm ci && npm run build
      - name: rsync release
        env:
          SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
        run: |
          # Key schreiben, rsync nach releases/$GITHUB_SHA, ln -sfn

Das volle Symlink-Skript liegt im Repo als bin/release.sh - der Workflow ruft es nur auf. Derselbe Skriptpfad funktioniert vom Laptop, wenn Actions ausfällt.

#Parallele WordPress-Deployments in GitHub Actions verhindern

Zwei schnelle Merges auf main starten zwei Workflow-Läufe. Ohne Sperre schreiben beide per rsync nach releases/ und schalten current in einer Reihenfolge um, die niemand gewählt hat. Eine concurrency-Gruppe in GitHub Actions erlaubt höchstens einen laufenden Workflow pro Gruppe; ein neu eingereihter Lauf wartet als pending (GitHub-Doku: Workflow-Parallelität steuern).

Für Deployments zählen zwei Details. Standardmäßig hält eine Gruppe einen laufenden und einen wartenden Lauf, und ein neuerer Lauf bricht den älteren wartenden ab: Der letzte Commit gewinnt, der mittlere wird übersprungen. cancel-in-progress: true würde auch den laufenden Job abbrechen und kann rsync mitten in einem Release-Verzeichnis stoppen. Für Produktion bleibt es bei false; true passt zu Test-Workflows auf Pull Requests, wo nur der neueste Commit zählt.

concurrency:
  group: deploy-production
  cancel-in-progress: false

Weil der Symlink erst nach vollständigem rsync umschaltet, berührt ein abgebrochener wartender Lauf current nie.

#Produktion mit GitHub-Actions-Umgebungen schützen

Ergänzen Sie environment: production im Deploy-Job und konfigurieren Sie die Umgebung in den Repository-Einstellungen. Dann greifen drei Schutzmechanismen (GitHub-Doku: Deployments und Umgebungen):

  • Erforderliche Reviewer: bis zu sechs Personen oder Teams, eine Freigabe genügt. Mit aktivierter Sperre gegen Selbstfreigabe kann die Person, die den Deploy gestartet hat, ihn nicht genehmigen.
  • Deployment-Branches und -Tags: Nur main oder Release-Tags dürfen nach production deployen, ein Workflow auf einem Feature-Branch erreicht den Produktionsserver also nicht.
  • Umgebungs-Secrets: nur für Jobs verfügbar, die die Umgebung referenzieren, und bei erforderlichen Reviewern erst nach der Freigabe. Der produktive DEPLOY_SSH_KEY gehört hierher statt in die Repository-Secrets.

Prüfen Sie vorher den Plan. In GitHub Free, Pro und Team funktionieren erforderliche Reviewer und Wartezeiten nur in öffentlichen Repositories. Deployment-Branches und Umgebungs-Secrets gehen in privaten Repositories mit Pro und Team, aber nicht mit Free. Agentur-Repositories für WordPress sind meist privat, auf diesen Plänen fehlt die Freigabe-Schranke also, und die Branch-Regeln tragen den Schutz.

#GitHub-Actions-Workflow für das Deployment härten

Der Deploy-Job hält einen SSH-Schlüssel zur Produktion, also verdient die Workflow-Datei dasselbe Review wie PHP-Code. GitHubs Referenz zur sicheren Nutzung nennt die Maßnahmen, die hier zählen:

  • Fremde Actions auf den vollständigen Commit-SHA pinnen. Ein Tag wie @v2 lässt sich verschieben oder löschen. Einen SHA umzubiegen bräuchte eine SHA-1-Kollision. Den SHA aus dem Repository der Action selbst nehmen, nicht aus einem Fork. GitHub nennt inzwischen eine Lockfile für Workflow-Abhängigkeiten als stärkere Option für Repositories, die sie einführen.
  • GITHUB_TOKEN minimal halten. permissions: contents: read oben setzen und nur pro Job erhöhen, wo ein Schritt mehr braucht. Ein rsync-Deploy über SSH braucht nur Lesezugriff auf das Repository.
  • Nicht vertrauenswürdige Eingaben aus run: heraushalten. Ein Pull-Request-Titel oder Branch-Name in ${{ }} innerhalb eines Shell-Skripts öffnet Skript-Injection. Den Wert über eine Zwischen-Umgebungsvariable übergeben.
  • Ein Secret pro Wert. Strukturierte Daten wie ein JSON-Block können die Maskierung in Logs aushebeln, deshalb Host, Benutzer, Pfad und Schlüssel als getrennte Secrets ablegen.

Dieselbe Seite weist darauf hin, dass nur Secrets maskiert werden, die im Job verwendet werden und für den Runner zugänglich sind. Abgeleitete Werte wie einen dekodierten Schlüssel also nie per echo ausgeben.

Dateien „in place“ unter public_html zu überschreiben heißt: ein paar Sekunden lang sieht die Hälfte der Requests altes functions.php und neues Template. Bei WooCommerce in der Black-Week-Woche kann das Warenkorb-Sessions zerstören.

Atomares Layout:

  • Basis: /var/www/site/
  • Releases: /var/www/site/releases/20260920-142211/
  • Shared: Uploads, wp-config.php, Object-Cache - außerhalb des Releases
  • current: Symlink auf den aktiven Release

Nach erfolgreichem rsync:

ln -sfn /var/www/site/releases/20260920-142211 /var/www/site/current

Nginx root zeigt auf .../current/public (oder das Äquivalent). Der Wechsel ist sofort. Alte Releases nach N Tagen löschen oder die letzten drei für Rollback behalten.

WordPress-Uploads müssen außerhalb des Releases liegen - sonst löscht jeder Deploy Medien oder kopiert Gigabytes. Klassiker: shared/uploads verlinkt nach wp-content/uploads in jedem Release.

#WordPress Staging und Deployment-Strategien im Vergleich

2026 ist der Weg vom Feature-Branch über Pull Request und Staging bis main und Produktion für Shops und Lead-Seiten nicht optional. Staging braucht:

  • dieselbe PHP-Version und dieselben Extensions wie Produktion
  • eine DB-Kopie (anonymisiert, wenn personenbezogene Daten unter der DSGVO liegen)
  • Payment-Secrets nur im Sandbox-Modus

Preview-URLs pro PR helfen bei Redesign und CSS, weniger bei Schema-Migrationen - die testen Sie auf Staging mit einem echten Dump.

StrategieRisikoPflegeaufwandWann sinnvoll
Manuelles FTPSehr hochGünstig starten, teure AusfälleNur Sandbox / Lernen
Git-Hook auf dem ServerMittelNiedrigKleines Portfolio, ein Entwickler
CI + atomares rsyncNiedrigMittelBusiness, WooCommerce, Agenturen
Blue/Green oder zwei VPSMinimalHochViel Traffic, SLA, Zahlungen

Blue/Green (zwei volle Umgebungen, Load-Balancer-Umschaltung) lohnt sich selten unter hunderten parallelen Sessions. Für die meisten DACH-Shops reicht atomarer Symlink plus Verzeichnis-Rollback - oft auf Hetzner oder einem Managed-Host mit SSH.

#Automatisierte Tests in einer WordPress-CI/CD-Pipeline

Eine Pipeline ohne Tests liefert kaputten Code nur schneller aus. Vier Ebenen passen zu einem WordPress-Repository, von schnell nach langsam:

  • Unit-Tests mit PHPUnit prüfen einzelne Funktionen eines Plugins oder Themes ohne Datenbank. Sie laufen bei jedem Push.
  • Integrationstests laden WordPress gegen eine temporäre Testdatenbank. wp scaffold plugin-tests erzeugt das Gerüst: phpunit.xml.dist, bin/install-wp-tests.sh für Testsuite und Datenbank, tests/bootstrap.php, einen Beispieltest und ein Regelwerk .phpcs.xml.dist. Standard ist eine CircleCI-Datei; --ci=github schreibt stattdessen eine Konfiguration für GitHub Actions (WP-CLI: wp scaffold plugin-tests).
  • Statische Analyse mit PHPStan und PHP_CodeSniffer findet Typfehler und Verstöße gegen Coding Standards, ohne den Code auszuführen.
  • End-to-End-Tests mit Playwright gehen echte Nutzerwege durch: Kontaktformular, WooCommerce-Warenkorb und Checkout. Sie sind die langsamste Ebene, also auf Pull Requests nach main und gegen Staging laufen lassen, nicht bei jedem Commit.

Ein roter Job auf irgendeiner Ebene stoppt den Workflow vor dem Artefakt-Schritt, und nichts erreicht den Server.

#Secrets und Datenbank-Migrationen beim WordPress-Deployment

Nie committen:

  • SSH-Keys
  • Datenbankpasswörter
  • AUTH_KEY / SECURE_AUTH_KEY aus wp-config.php
  • API-Tokens von Payment-Gateways (PayPal, Stripe, deutsche PSP)

In GitHub liegen sie unter Settings, dann Secrets and variables, dann Actions. Als env im Deploy-Schritt injizieren. Auf dem Server liegt wp-config.php unter shared/ und ist kein Teil des CI-Artefakts.

WP-CLI nach dem Symlink-Wechsel:

  • wp cache flush bei Object Cache
  • wp rewrite flush nach CPT-Änderungen
  • wp plugin list als Smoke-Zeile im Log

#WP-CLI vom Runner aus auf dem Produktionsserver ausführen

Diese Befehle müssen auf dem Server laufen, gegen den neuen Release. WP-CLI erledigt das vom Runner aus mit dem globalen Parameter --ssh ([<scheme>:][<user>@]<host>[:<port>][<path>]) oder mit Aliasen in der projekteigenen wp-cli.yml (WP-CLI-Handbuch: Befehle remote ausführen):

@staging:
  ssh: [email protected]/var/www/site/current/public
@prod:
  ssh: [email protected]/var/www/site/current/public

Mit dieser Datei im Repository läuft wp @prod cache flush auf der Produktion. WP-CLI muss trotzdem auf dem Server installiert und als wp aufrufbar sein: Der Runner reicht den Befehl nur per SSH durch.

Weitere Befehle für den Schritt nach dem Umschalten, alle in der WP-CLI-Befehlsreferenz:

  • wp core is-installed gibt nichts aus und antwortet über den Exit-Code, eine fehlgeschlagene Prüfung lässt den Schritt also scheitern.
  • wp core update-db --dry-run vergleicht die Datenbankversionen vor dem echten wp core update-db nach einem Core-Update.
  • wp core verify-checksums gleicht die Core-Dateien mit den Prüfsummen von WordPress.org ab und findet Dateien, die außerhalb von Git geändert wurden.
  • wp maintenance-mode activate und deactivate decken den seltenen Release ab, der das Schema ändern muss, während nichts hineinschreibt.

Datenbank-Migrationen getrennt vom Datei-Deploy planen. Symlink-Rollback macht kein ALTER TABLE rückgängig. Bei destruktiven Migrationen: zuerst Backup (wp db export auf Staging und Produktion), dann Migration, dann Traffic auf Code, der das Schema braucht - oder Feature-Flag in PHP.

PHP-Abhängigkeiten: Composer install - in CI für Produktion immer --no-dev und gesperrtes composer.lock.

#Häufige Fehler in der WordPress-Deployment-Pipeline

Aus Praxis auf VPS (Hetzner, DigitalOcean, OVH) und Managed mit SSH:

  • .gitignore frisst vendor/ - Produktion bekommt ein Theme ohne Autoloader. Entweder Vendor auf dem Runner bauen und ins Artefakt packen, oder Composer nach dem rsync auf dem Server laufen lassen (dann braucht der Server Composer und Packagist-Zugang).
  • Falsche Pfade - Skript erwartet /var/www/html, Hosting nutzt /home/user/domains/.... Pfade in Secrets pro Umgebung pinnen.
  • Opcache hält alten Code - nach ln -sfn PHP-FPM reloaden oder opcache_reset per WP-CLI/mu-Plugin nur für den Deploy-User.
  • Cron und Queues - Action Scheduler von WooCommerce kann Jobs noch Minuten auf altem Code fahren; nach großen Releases Failed Jobs kurz beobachten.

Smoke-Test nach dem Deploy (curl vom Runner oder eigener Job):

  • Startseite HTTP 200
  • /wp-login.php 200
  • eine kritische Produkt- oder Formular-URL
  • optional HEAD an das CDN bei gehashten Assets

Schlägt Smoke fehl, ist automatisches Symlink-Rollback billiger als der Kundenanruf um 23:00.

#Block-Themes und MU-Plugins mit Git deployen

Nicht jedes WordPress-Stück passt in dieselbe Pipeline. Inhalte in der Datenbank (Beiträge, ACF-Field-Groups ohne JSON-Export, Elementor-CSS) leben außerhalb des Releases. CI/CD schützt Code, ersetzt kein DB-Backup.

Praktische Trennung:

  • Klassisches oder hybrides Theme mit Vite - voller CI-Build, Artefakt mit style.css + dist/.
  • Block-Theme (FSE) - theme.json und HTML-Templates in Git; Änderungen aus dem Site-Editor zurück per PR, sonst divergieren Produktion und Git nach dem ersten „Speichern“.
  • Must-Use-Plugins - mit dem Release ausrollen; nicht aus dem Admin updaten. Guter Ort für Deploy-Healthchecks und das Abschalten des Dateieditors.
  • Plugins von wordpress.org - Versionen per Composer (wpackagist) pinnen oder in einem reviewed Job aktualisieren. „Update im Admin“ gemischt mit „CI überschreibt plugins/“ endet in einem Zufallsbaum.

Agentur-Stacks im DACH-Raum mischen oft Custom-Theme, WooCommerce aus wpackagist und zwei Premium-ZIPs über ein Composer-Path-Repository. Die Pipeline muss alle drei Quellen kennen, sonst unterscheiden sich Staging und Produktion um ein ZIP von vor einem halben Jahr.

#Checkliste für WordPress Continuous Deployment

Bevor main an Produktion hängt, diese Liste einmal durchgehen - spart ein Wochenende:

  1. Privates Repo oder Historie ohne Secrets (git log -p zeigt keine alten .env).
  2. Branch Protection: Pflicht-PR, grüner test-Workflow.
  3. Getrennte Secrets: DEPLOY_HOST_STAGING, DEPLOY_HOST_PROD, eigene SSH-Keys.
  4. Staging mit derselben PHP-Version wie Produktion (nicht „wir 8.3, Kunde 8.1“).
  5. DB-Backup vor dem ersten atomaren Umschalten - auch wenn Code-Rollback steht.
  6. Uptime-Monitoring (UptimeRobot, Better Stack o. Ä.) mit SMS/Slack auf die Produktions-URL.
  7. Einseitiges Runbook: manuelles ln -sfn auf den vorherigen Release, wer Serverzugriff hat.

Erst dann Auto-Deploy von main. Bis dahin reichen „Build + Test“ auf PRs und manueller workflow_dispatch auf Staging.

#Zusammenfassung

CI/CD für WordPress ist kein „magisches YAML“, sondern ein wiederholbarer Vertrag: dasselbe PHP, derselbe Lockfile, dasselbe Artefakt, Umschalten ohne Fenster halb hochgeladener Dateien. Sie starten mit Git und Staging, legen Actions für Composer/npm drauf und enden bei atomarem current plus Smoke-Test. FTP wird Notfallwerkzeug, nicht Prozess.

Wenn Sie für Shop oder Lead-Seite einen WordPress-Entwickler brauchen, der die Pipeline neben dem Theme-Code hält, arbeitet WPPoland am realen Stack - nicht an Folien.

Nächster Schritt

Machen Sie aus dem Artikel eine echte Umsetzung

Dieser Block stärkt die interne Verlinkung und führt Nutzer gezielt zum nächsten sinnvollen Schritt im Service- und Content-System.

Soll das Thema auf Ihrer Website umgesetzt werden?

Wenn Sie aus dem Artikel konkrete Maßnahmen für Website, Relaunch oder Weiterentwicklung ableiten wollen, definiere ich den Scope und setze ihn um.

Weitere WordPress-Dienste und Wissensbasis entdecken

Stärken Sie Ihr Unternehmen mit professionellem technischen Support in den Kernbereichen des WordPress-Ökosystems.

Häufig gestellte Fragen

Praktische Antworten zur Umsetzung des Themas.

Lohnt sich CI/CD für einen einzelnen Freelancer?#
Ja. Einzelentwickler verlieren am meisten durch eine vergessene PHP-Datei oder ein composer.lock von einer anderen PHP-Version. Die Pipeline erzwingt denselben Build bei jedem Commit und hinterlässt ein prüfbares Log, welches SHA live ging.
Was ist Zero-Downtime-Deployment bei WordPress?#
Neuer Code landet in releases/TIMESTAMP. Erst nach erfolgreichem rsync und optionalem wp cache flush wird der Symlink current umgestellt. PHP-FPM oder Nginx bedienen über current - der Wechsel dauert Millisekunden und braucht keinen Wartungsmodus.
Brauche ich einen VPS für CI/CD?#
VPS oder Container geben volle Kontrolle (SSH, Symlinks, WP-CLI). Auf Managed-Hosting bleibt oft eine Deploy-API oder SFTP mit Key in Secrets - immer noch besser als manuelles FileZilla, auch ohne echtes Blue/Green.
Was tun, wenn der Deploy scheitert?#
Halten Sie N ältere Release-Verzeichnisse. Schlägt der Smoke-Test mit 500 fehl oder fehlt vendor/, zeigen Sie den Symlink wieder auf den vorherigen Release. Datenbank-Migrationen planen Sie getrennt - Code-Rollback macht kein ALTER TABLE rückgängig.
Wo baue ich Themes mit Vite oder webpack?#
Auf dem CI-Runner: Checkout, Node einrichten, npm ci, npm run build, dann dist/ zusammen mit PHP ins Artefakt. Auf Produktion gehören weder node_modules noch TypeScript-Quellen - nur kompiliertes CSS/JS.

Sie brauchen ein FAQ für Branche und Zielmarkt? Ich erstelle eine Version passend zu Ihren Business-Zielen.

Kontakt aufnehmen

Ähnliche Artikel