Bereitstellen und CI/CD
cipi deploy
Cipi verwendet Bereitsteller für alle Einsätze. Jede Bereitstellung ist atomar: eine neue Version
Das Verzeichnis wird vor dem vollständig vorbereitet current Der symbolische Link wird vertauscht, der Datenverkehr also nie
unterbrochen.
cipi deploy und cipi deploy --rollback
Abbruch mit einer klaren Upgrade-Meldung vor Aufrufen von Deployer, wenn eine App noch angeheftet ist
auf eine ältere PHP-Version – wechseln Sie mit cipi app edit <app> --php=8.3 (oder
höher) zuerst.Pipeline bereitstellen
Deployer und Composer laufen mit dem Die konfigurierte PHP-Version der App (z.B.
/usr/bin/php8.5), nicht der Systemstandard. Dies gilt für cipi deploy,
cipi deploy --rollback, Crontab-Bereitstellungstrigger, cipi sync import setzt ein,
und die deploy / composerAliase in den App-Benutzern .bashrc.
- Warteschlangenarbeiter stoppen (
cipi worker stop) - Klonen Sie das Repo in
releases/N/ - Lauf
composer install --no-dev(mit PHP der App) - Link
shared/.envundshared/storage/ - Lauf
artisan migrate --force - Lauf
artisan optimize - Lauf
artisan storage:link - Tauschen
currentSymlink atomar - Starten Sie die Warteschlangenarbeiter neu
- Alte Veröffentlichungen bereinigen (die letzten 5 behalten)
$ cipi deploy myapp # deploy latest commit $ cipi deploy myapp --rollback # instant rollback to previous release $ cipi deploy myapp --releases # list all releases with timestamps $ cipi deploy myapp --key # show the SSH deploy key $ cipi deploy myapp --webhook # show webhook URL and token $ cipi deploy myapp --unlock # remove a stuck deploy lock $ cipi deploy myapp --snapshot # v5.0+ opt-in DB dump before deploy $ cipi deploy myapp --snapshot-required # fail if snapshot cannot be taken $ cipi deploy myapp --trust-host=git.mycompany.com # trust a custom Git server fingerprint $ cipi deploy myapp --trust-host=git.mycompany.com:2222 # trust on non-standard port (also writes ~/.ssh/config)
Seitdem v5.0, Opt-in DB-Snapshots vorab bereitstellen sind erhältlich über
--snapshot / --snapshot-required oder eine permanente App-Einstellung – siehe
Stellen Sie DB-Snapshots vorab bereit. Octane Apps verwenden die
laravel-octane.php Deployer-Vorlage (Octane bei der Bereitstellung neu laden/neu starten); Knoten aktivieren
baut mit cipi app edit <app> --node-build='…'.
cipi deploy myapp --unlock um es vor der erneuten Bereitstellung zu entfernen.Stellen Sie DB-Snapshots vorab bereit
Seitdem v5.0, cipi deploy <app> kann die Datenbank sichern
vor Die Release-Pipeline wird ausgeführt. Schnappschüsse landen darunter
/var/log/cipi/backups/ – derselbe Pfad, den auch verwendet wird
cipi db backup.
$ cipi deploy shop --snapshot # dump first; warn and continue on failure $ cipi deploy shop --snapshot-required # dump first; abort deploy if snapshot fails
Was passiert
- Bevor Deployer startet, erstellt Cipi einen DB-Dump
/var/log/cipi/backups/. - Mit
--snapshot-required, ein fehlgeschlagener Dump (oder eine fehlende DB-Engine) Blöcke die Bereitstellung. - Mit
--snapshotAllein bei einem fehlgeschlagenen Dump wird eine Warnung und die Bereitstellung ausgegeben geht weiter.
Bei jeder Bereitstellung aktivieren
Aktivieren Sie es dauerhaft für eine App, damit bei jeder Bereitstellung (CLI, webhook oder Pipeline) zuerst ein Snapshot erstellt wird:
$ cipi app edit shop --predeploy-snapshot
cipi deploy --rollback stellt das Vorherige wieder her Code Nur Freigabe.
Das tut es nicht die Datenbank wiederherstellen. Wenn Sie den Pre-Deploy-Dump zurück benötigen, verwenden Sie
cipi db restore.Für Pipeline-Workflows, die auch archivieren shared/ bis S3 vor der Veröffentlichung, siehe
Sichere Bereitstellung – Sicherung vor der Veröffentlichung.
cipi app deploy-config
Seitdem v5.0.3, verwalten Sie dauerhafte Deployer-Rezeptoptionen, die in gespeichert sind
apps.json und durch Regenerieren angewendet deploy.php aus der Vorlage –
eine sichere Alternative zum Bearbeiten von Freiform-PHP.
$ cipi app deploy-config myapp $ cipi app deploy-config myapp --keep-releases=5 $ cipi app deploy-config myapp --migrate --optimize --storage-link $ cipi app deploy-config myapp --no-migrate --no-optimize $ cipi app deploy-config myapp --queue-restart --horizon-terminate $ cipi app deploy-config myapp --extra-artisan=view:clear,event:cache $ cipi app deploy-config myapp --node-build='npm ci && npm run build' $ cipi app deploy-config myapp --predeploy-snapshot
RUHE: GET|PUT /api/apps/{name}/deploy-config (Fähigkeit
apps-deploy-config, API 1.14+ / Cipi 5.0.3+).
MCP: AppDeployConfigShow, AppDeployConfigUpdate.
auth.json
Verwalten Sie die auth.json Datei für eine App. Diese Datei befindet sich unter
/home/<app>/shared/auth.json und wird automatisch mit jeder Veröffentlichung von verknüpft
Deployer – genau so .env. Verwenden Sie es, um strukturierte Anmeldedaten zu speichern (z. B. API
Schlüssel, Feature-Flags oder jede JSON-Nutzlast), die Ihre Laravel-App zur Laufzeit lesen kann.
$ cipi auth create myapp # create auth.json with initial { "users": [] } structure $ cipi auth edit myapp # open in $EDITOR (fallback: nano), validate JSON on close $ cipi auth show myapp # print contents formatted with jq $ cipi auth delete myapp # delete file (asks for confirmation) # Non-interactive (v5.0.3+) — API / scripts / GUI $ cipi auth create myapp --force $ cipi auth edit myapp --file=/tmp/auth.json $ cipi auth show myapp --json $ cipi auth delete myapp --force
RUHE: GET|POST|PUT|DELETE /api/apps/{name}/auth (Fähigkeit apps-auth, API
1.14+) – Composer/strukturiertes JSON, verschieden von HTTP Basic Auth.
MCP: AppAuthJsonShow, AppAuthJsonCreate,
AppAuthJsonUpdate, AppAuthJsonDelete.
Befehlsdetails
| Befehl | Beschreibung |
|---|---|
cipi auth create <app> |
Erstellt shared/auth.json mit der Ausgangsstruktur
{"users":[]}, setzt Berechtigungen auf 640 (Inhaber
app:app) und fügt hinzu auth.json zu
shared_files in der Deployer-Konfiguration der App, sodass es bei jedem symbolisch verknüpft ist
bereitstellen.
|
cipi auth edit <app> |
Öffnet shared/auth.json in $EDITOR (fällt zurück auf
nano). Nachdem der Editor geschlossen wurde, wird JSON mit validiert
jq und warnt, wenn die Datei fehlerhaft ist.
|
cipi auth show <app> |
Druckt den Inhalt von shared/auth.json formatiert mit
jq.
|
cipi auth delete <app> |
Bittet um Bestätigung und löscht dann shared/auth.json und entfernt die
auth.json Eintrag von shared_files im Deployer der App
config.
|
Deployer-Integration
cipi auth create automatisch angehängt auth.json zum
shared_files Liste in /home/<app>/.deployer/deploy.php, und
cipi auth delete entfernt es. Dies bedeutet, dass die Datei genauso behandelt wird
.env: Es bleibt über alle Releases hinweg bestehen und wird nie durch eine Bereitstellung überschrieben.
cipi auth Der Vorgang wird über protokolliert log_action für
Überprüfbarkeit. Die AUTH Abschnitt ist auch in der Ausgabe von aufgeführt
cipi help.
Git-Anbieter
Cipi ist einsatzbereit GitHub und GitLab aber es unterstützt alle anderer Git-Anbieter, der SSH-Bereitstellungsschlüssel unterstützt – keine Anbieterbindung.
Für self-hosted oder benutzerdefinierte Git-Server müssen Sie zuvor dem Host-Fingerabdruck des Servers vertrauen
Der Bereitsteller kann über SSH klonen. Benutzen Sie die --trust-host Flag zum Hinzufügen des Fingerabdrucks zum
App-Benutzer ~/.ssh/known_hosts automatisch:
# show the deploy key and add it to your Git provider $ cipi deploy myapp --key # trust a custom Git server fingerprint (standard port) $ cipi deploy myapp --trust-host=git.mycompany.com # trust a custom Git server on a non-standard port # (also writes ~/.ssh/config automatically) $ cipi deploy myapp --trust-host=git.mycompany.com:2222
Host / Port Zugang zum App-Benutzer ~/.ssh/config also
dass der Deployer den Server ohne zusätzliche Konfiguration erreichen kann.
Git-Auto-Setup
Wenn Sie a speichern GitHub oder GitLab Persönliches Zugriffstoken, Cipi
fügt bei jeder Ausführung automatisch den SSH-Bereitstellungsschlüssel hinzu und erstellt webhook im Repositorycipi app create. Keine manuellen Schritte erforderlich.
Speichern Sie einen Token
# GitHub (fine-grained or classic PAT) $ cipi git github-token ghp_xxxxxxxxxxxxxxxxxxxx # GitLab (gitlab.com) $ cipi git gitlab-token glpat-xxxxxxxxxxxxxxxxxxxx # GitLab (self-hosted — set the URL before or after the token) $ cipi git gitlab-url https://gitlab.example.com $ cipi git gitlab-token glpat-xxxxxxxxxxxxxxxxxxxx
GitHub Token-Berechtigungen
Feinkörnige Token (empfohlen) erforderlich Verwaltung und
Webhooks eingestellt auf Lesen und schreiben auf den Zielrepositorys. Klassische Token
brauche das repo Umfang.
GitLab Token-Berechtigungen
Die api Der Umfang ist das erforderliche Minimum – GitLab bietet keinen detaillierteren Umfang
Dies deckt sowohl Bereitstellungsschlüssel als auch Webhooks ab.
Automatischer Lebenszyklus
| Veranstaltung | Was Cipi automatisch macht |
|---|---|
app create |
Fügt den Bereitstellungsschlüssel hinzu und erstellt webhook im Repository über API. Die Zusammenfassung zeigt „automatisch konfiguriert ✓“ statt manueller Anleitung. |
app edit --repository=... |
Entfernt den Bereitstellungsschlüssel + webhook aus dem alten Repository und fügt sie dann dem neuen hinzu. |
app delete |
Entfernt den Bereitstellungsschlüssel + webhook aus dem Repository, bevor die App gelöscht wird. |
cipi git Befehle
| Befehl | Beschreibung |
|---|---|
cipi git status |
Zeigen Sie den Verbindungsstatus des Anbieters und die Integrationsdetails pro App an (Bereitstellungsschlüssel-ID, webhook ID) |
cipi git github-token <token> |
Speichern Sie ein GitHub persönliches Zugriffstoken |
cipi git gitlab-token <token> |
Speichern Sie ein GitLab persönliches Zugriffstoken |
cipi git gitlab-url <url> |
Legen Sie die Basis-URL für eine self-hosted GitLab-Instanz fest |
cipi git remove-github |
Entfernen Sie das gespeicherte GitHub-Token |
cipi git remove-gitlab |
Entfernen Sie das gespeicherte GitLab-Token und die URL |
Manuelle Einrichtung (Fallback)
Die automatische Einrichtung wird übersprungen, wenn kein Token konfiguriert ist, wenn der API-Aufruf fehlschlägt (falsche Berechtigungen, Repository nicht gefunden, Ratenbegrenzung) oder wenn das Repository bei einem anderen Anbieter als gehostet wird GitHub oder GitLab (z. B. Gitea, Forgejo, Bitbucket). In all diesen Fällen greift Cipi auf zurück Der manuelle Workflow erfolgt und die App-Erstellung verläuft normal.
So konfigurieren Sie den Bereitstellungsschlüssel und webhook manuell:
# print the SSH deploy key to add to your Git provider $ cipi deploy myapp --key # print the webhook URL and token $ cipi deploy myapp --webhook # if using a custom Git server, trust the host fingerprint first $ cipi deploy myapp --trust-host=git.mycompany.com
Fügen Sie sie dann in den Repository-Einstellungen Ihres Anbieters hinzu:
- Schlüssel bereitstellen — GitHub: Einstellungen → Schlüssel bereitstellen → Bereitstellungsschlüssel hinzufügen; GitLab: Einstellungen → Repository → Schlüssel bereitstellen
- Webhook — GitHub: Einstellungen → Webhooks → webhook hinzufügen;
GitLab: Einstellungen → Webhooks → Neues webhook hinzufügen. Legen Sie die Payload-URL fest und
Geheimnis der von gezeigten Werte
cipi deploy myapp --webhook
Anpassen des Bereitstellungsskripts
Die Bereitstellungskonfiguration für jede App wird gespeichert unter:
Diese Datei wird von Cipi automatisch generiert app create und automatisch aktualisiert, wenn Sie
Ändern Sie die PHP-Version oder stellen Sie den Zweig bereit über cipi app edit. Sie können es bearbeiten, um es anzupassen
die Bereitstellungspipeline, aber Sie sollten die Auswirkungen verstehen, bevor Sie dies tun.
Standardbereitstellungspipeline
Die automatisch generierte deploy.php führt diese Aufgaben der Reihe nach aus:
deploy:prepare // create releases/N/ directory deploy:vendors // composer install --no-dev deploy:shared // link shared/.env and shared/storage/ artisan:migrate // php artisan migrate --force artisan:optimize // php artisan optimize artisan:storage:link // php artisan storage:link deploy:symlink // swap current → releases/N/ atomically cipi:restart-workers // supervisorctl restart myapp-* deploy:cleanup // keep last 5 releases, delete older
Benutzerdefinierte Aufgaben hinzufügen
Sie können Aufgaben vor oder nach jedem Schritt hinzufügen. Für ein vollständiges Frontend-Build-Beispiel (npm install && npm run build), siehe
Aufbau von Frontend-Assets unten. Weitere häufige Beispiele:
// Run artisan db:seed after migrations after('artisan:migrate', 'artisan:db:seed'); // Clear view cache after symlink swap after('deploy:symlink', 'artisan:view:clear'); // Custom task — send a Slack notification task('notify:slack', function () { run('curl -X POST https://hooks.slack.com/... -d \'{"text":"Deployed!"}\''); }); after('deploy:symlink', 'notify:slack');
Erstellen von Frontend-Assets (npm / Vite)
Es gibt keine dedizierte cipi CLI Flag für Frontend-Builds (z. B. npm install && npm run build).
Anpassen deploy.php ist der unterstützte und erwartete Ansatz – Definiere a
Bereitsteller task() und haken Sie es ein after() oder before(). Das tust du nicht
Dies muss vermieden werden; Die Erweiterung der Pipeline ist genau das, wofür die Datei gedacht ist.
Cipi wird installiert Node.js und npm auf dem Server während der Einrichtung. Stellen Sie sicher, dass sie verfügbar sind als der App-Benutzer:
$ ssh myapp@your-server-ip
myapp@server:~$ node -v && npm -v
Begehen package.json und package-lock.json zu Ihrem Repository. Haken Sie den Build ein
danach deploy:shared also .env ist verlinkt (Vite liest
VITE_* Variablen von dort) und vor deploy:symlink also
Kompilierte Assets sind in der Version vorhanden, bevor sie live geht.
Hängen Sie den Block unten an unten von
/home/myapp/.deployer/deploy.php, unten die automatisch generierten Aufgabendefinitionen von Cipi:
// ── Custom: frontend build (safe zone — keep below Cipi-managed blocks) ── task('npm:build', function () { cd('{{release_path}}'); run('npm ci --no-audit --no-fund && npm run build'); }); // .env is linked → build assets → then migrations / optimize / symlink after('deploy:shared', 'npm:build');
Dies entspricht dem Äquivalent von npm install && npm run build bei jedem Einsatz. Bevorzugen
npm ci in der Produktion wann package-lock.json ist verpflichtet – es ist schneller und
reproduzierbar. Benutzen npm install stattdessen nur, wenn Sie Abhängigkeiten nicht sperren.
Wenn Sie separate Installations- und Build-Schritte benötigen (z. B. zum Zwischenspeichern). node_modules über Veröffentlichungen hinweg),
Teilen Sie sie in zwei Aufgaben auf:
task('npm:ci', function () {
cd('{{release_path}}');
run('npm ci --no-audit --no-fund');
});
task('npm:build', function () {
cd('{{release_path}}');
run('npm run build');
});
after('deploy:shared', 'npm:ci');
after('npm:ci', 'npm:build');
Um nachfolgende Bereitstellungen zu beschleunigen, können Sie Abhängigkeiten über Releases hinweg beibehalten, indem Sie sie hinzufügen
node_modules in die freigegebenen Verzeichnisse des Deployers (optional – nur wenn Ihr Projekt dies unterstützt).
es):
add('shared_dirs', ['node_modules']);
Bearbeiten Sie die Datei auf dem Server als App-Benutzer und testen Sie sie dann mit cipi deploy myapp:
$ ssh myapp@your-server-ip myapp@server:~$ nano ~/.deployer/deploy.php # paste the custom tasks at the bottom, save, then as root: $ cipi deploy myapp
npm ci && npm run build in GitHub Aktionen
oder GitLab CI vor Der SSH-Bereitstellungsschritt wird ausgeführt, sodass der Server nur vorgefertigte Assets erhält.
Siehe CI/CD Pipelines – SSH-Bereitstellung.Ausführen zusätzlicher artisan-Befehle
// Seed only in specific environments
task('artisan:db:seed', function () {
run('{{bin/php}} {{release_path}}/artisan db:seed --force');
});
cipi app edit myapp --php=X oder cipi app edit myapp --branch=X. Sichern
Ihre Anpassungen oder bewahren Sie sie in einem Abschnitt auf, der klar von den Cipi-verwalteten Blöcken getrennt ist. A
Ein sicheres Muster besteht darin, alle benutzerdefinierten Aufgaben am Ende der Datei nach der Standardaufgabe zu platzieren
Definition.
Deaktivieren eines Standardschritts
Um eine Aufgabe zu überspringen – beispielsweise wenn Sie Migrationen manuell durchführen – kommentieren Sie sie aus oder entfernen Sie sie aus der
deploy Aufgabendefinition:
// Remove the migrate step from the pipeline task('deploy', [ 'deploy:prepare', 'deploy:vendors', 'deploy:shared', // 'artisan:migrate', ← disabled 'artisan:optimize', 'artisan:storage:link', 'deploy:symlink', 'cipi:restart-workers', 'deploy:cleanup', ]);
Testen Sie Ihre Änderungen
Nach der Bearbeitung deploy.php, führen Sie immer eine Testbereitstellung durch, bevor Sie in die Produktion gehen:
$ cipi deploy myapp # If something goes wrong, instant rollback: $ cipi deploy myapp --rollback # If the deploy is stuck (e.g. interrupted mid-run): $ cipi deploy myapp --unlock
~/logs/deploy.log oder über
cipi app logs myapp --type=deploy. Überprüfen Sie es zuerst, wenn Sie einen Fehler beheben
bereitstellen.
Bereitstellen & CI/CD – Übersicht
Mit Cipi, CI (bauen und testen) und CD (Freigabe zur Produktion) können
geteilt oder kombiniert werden. Letztendlich läuft jede Bereitstellung gleich ab Bereitsteller
Pipeline auf dem Server – Klonen, composer install, Migrationen, Symlink-Tausch,
Neustart des Arbeiters. Was sich ändert ist was auslöst diese Pipeline.
Cipi unterstützt zwei Triggermodelle. Beginnen Sie bei den meisten Laravel-Apps mit webhook + Cipi Agent Weg. Wechseln Sie zu einer vollständigen CI/CD-Pipeline, wenn Sie Gates, Backups usw. benötigen Infrastruktur-Orchestrierung, die ein einfacher Push-Hook nicht ausdrücken kann.
Zwei Möglichkeiten, eine Bereitstellung auszulösen
| Webhook + Cipi Agent (empfohlen) | CI/CD-Pipeline über SSH | |
|---|---|---|
| Auslöser | Git-Anbieter postet an /cipi/webhook auf Druck |
GitHub Aktionen / GitLab CI-Job wird ausgeführt cipi deploy über SSH |
| Serverzugriff von CI | Keine – nur HTTPS für Ihre App-Domain | Dedizierter SSH-Schlüssel, der als CI-Geheimnis gespeichert ist |
| Tests vor der Bereitstellung | Lokal oder in einem separaten CI-Job ausführen; „Deploy“ wird immer noch beim Push ausgelöst, es sei denn, Sie deaktivieren es webhook | Nativ – Der Bereitstellungsschritt wird erst danach ausgeführt needs: test (oder gleichwertige) Prüfungen |
| Backup vor Veröffentlichung | Manuell oder cron auf dem Server | Pipeline-Job – siehe sicher bereitstellen |
| Vorschau/Überprüfung von Apps | Wird standardmäßig nicht unterstützt | Pipeline erstellt pro Zweig Cipi Apps – siehe Vorschau Umgebungen |
| Komplexität der Einrichtung | Niedrig – composer require cipi/agent + ein webhook |
Mittel – SSH-Schlüssel, Geheimnisse, Workflow YAML |
Welchen Ansatz soll ich verwenden?
| Anwendungsfall | Empfohlener Ansatz | Wo kann man mehr lesen? |
|---|---|---|
Einzelne Laravel-App, Push-to-Deploy auf main |
Webhook + Agent | Webhook-Setup |
| Nur bereitstellen, wenn die CI-Tests erfolgreich sind | Pipeline-SSH (Produktion webhook deaktivieren) | Pipeline-SSH-Bereitstellung |
| DB + Dateisicherung vor jeder Produktionsfreigabe | Pipeline-SSH | Sichere Bereitstellung mit Backup |
| Slack-/Telegram-Benachrichtigungen zum Bereitstellungsergebnis | Pipeline-SSH | Stellen Sie Benachrichtigungen bereit |
| Kurzlebige URL pro Funktionszweig (Apps bewerten) | Pipeline-SSH | Vorschauumgebungen |
| Stellen Sie mehrere Apps über ein Repository auf einem Server bereit | Entweder – webhook pro App oder eine Pipeline mit Parallelität cipi deploy |
Multi-App-Bereitstellung |
cipi deploy myapp --unlock wenn ein festsitzendes Schloss zurückbleibt.
Automatische Bereitstellungen – Cipi Agent & webhook
cipi-Agent (cipi/agent) ist ein Laravel-Paket, das verfügbar macht
POST /cipi/webhook in Ihrer laufenden Anwendung. Wenn GitHub oder GitLab einen Push sendet
Bei diesem Ereignis validiert der Agent die Payload-Signatur, bestätigt sie sofort und stellt eine Bereitstellung in die Warteschlange
der Server – kein SSH vom CI-Runner, nein sudo, keine offenen eingehenden Ports über HTTPS hinaus.
So funktioniert der webhook-Flow
Das Design trennt schnelle HTTP Bestätigung von langsamer Deployer Arbeit. Eine Bereitstellung kann mehrere Minuten dauern. Git-Anbieter überschreiten webhook HTTP Aufrufe nach ca. 10 Sekunden. Cipi löst dieses Problem mit einer Flag-Datei und der Crontab des App-Benutzers.
Developer Git provider Your Laravel app (Cipi Agent) Server (app user cron)
│ │ │ │
│ git push main │ │ │
│ ───────────────────────────► │ │ │
│ │ POST /cipi/webhook │ │
│ │ (signed with secret) │ │
│ │ ───────────────────────────► │ │
│ │ │ 1. Verify CIPI_WEBHOOK_TOKEN │
│ │ │ 2. Check branch (CIPI_DEPLOY_BRANCH) │
│ │ │ 3. Write ~/.deploy-trigger │
│ │ ◄─────────────────────────── │ 4. Return 200 immediately │
│ │ │ │
│ │ │ every minute (* * * * *) │
│ │ │ ◄──────────────────────────────────────│
│ │ │ cron sees .deploy-trigger │
│ │ │ removes file, runs Deployer │
│ │ │ in background as app user │
│ │ │ │
│ │ │ clone → composer → migrate │
│ │ │ → symlink swap → workers │
Der Deployer wird immer als ausgeführt app Linux-Benutzer (z.B. myapp), mit dem
Korrekte PHP-Binär- und Dateiberechtigungen – derselbe Kontext wie ein Handbuch
cipi deploy myapp. Der webhook wird niemals direkt an den Deployer ausgezahlt; es lässt nur das fallen
Triggerdatei, die von der Crontab von Cipi bereits überwacht wird.
Voraussetzungen
| Anforderung | Warum |
|---|---|
| Cipi App, erstellt mit Git-Repository | Der Bereitstellungsschlüssel muss das Repo klonen – siehe Git-Auto-Setup |
| Mindestens eine erfolgreiche manuelle Bereitstellung | Das Agentenpaket muss in der Datei vorhanden sein current Veröffentlichung vor dem webhook
Route existiert |
composer require cipi/agent im Projekt |
Registriert die /cipi/webhook Routen- und Signaturvalidierung |
| Webhook URL erreichbar über HTTPS | Git-Anbieter benötigen eine öffentliche URL; verwenden cipi ssl install zuerst |
CIPI_WEBHOOK_TOKEN in shared/.env |
Automatisch generiert um cipi app create; in allen Versionen geteilt |
Schritt-für-Schritt-Einrichtung
1. Erstellen Sie die App und stellen Sie sie einmal manuell bereit damit der Server Ihr Repository klonen kann:
$ cipi app create --user=myapp --domain=myapp.com \ --repository=git@github.com:you/myapp.git --branch=main --php=8.5 $ cipi deploy myapp
2. Installieren Sie den Cipi Agent in Ihrem Laravel-Projekt lokal festschreiben und pushen:
$ composer require cipi/agent $ git add composer.json composer.lock $ git commit -m "Add Cipi Agent for webhook deploys" $ git push origin main $ cipi deploy myapp # one more manual deploy until webhook is live
3. Konfigurieren Sie webhook. Wenn Sie ein GitHub- oder GitLab-Token gespeichert haben, ist möglicherweise Cipi vorhanden
webhook wurde bereits erstellt app create – erkundigen Sie sich bei
cipi git status. Andernfalls rufen Sie die URL und das Geheimnis ab:
$ cipi deploy myapp --webhook
Fügen Sie webhook in Ihrem Git-Anbieter hinzu:
| Anbieter | Payload-URL | Geheimes Feld | Veranstaltungen |
|---|---|---|---|
| GitHub | https://myapp.com/cipi/webhook |
Geheimnis → Wert von --webhook |
Nur die push Ereignis |
| GitLab | https://myapp.com/cipi/webhook |
Geheimer Token → gleicher Wert | Push-Events |
4. Beschränken Sie sich auf Ihren Bereitstellungszweig (für die Produktion empfohlen):
CIPI_DEPLOY_BRANCH=main
Stellen Sie dies ein shared/.env über cipi app env myapp. Pusht auf andere Zweige
erhalten Sie eine skipped Antwort und keine Bereitstellungsläufe.
5. Überprüfen Sie. Pushen Sie ein kleines Commit main und sehen Sie sich das Bereitstellungsprotokoll an:
$ cipi app logs myapp --type=deploy # or on the server as the app user: $ tail -f /home/myapp/logs/deploy.log
Innerhalb von etwa einer Minute nach der Zustellung von webhook sollte eine neue Deployer-Version erscheinen. Bestätigen Sie das
Live-Commit mit php artisan cipi:status oder die Gesundheit
überprüfen Endpunkt.
Git-Auto-Setup
Wenn ein GitHub oder GitLab Token ist auf dem Server konfiguriert, Cipi
Registriert den Bereitstellungsschlüssel und erstellt den webhook automatisch bei jedem
cipi app create. Die App-Zusammenfassung wird angezeigt „automatisch konfiguriert ✓“ statt manuell
Anweisungen. Lebenszyklusereignisse (app edit --repository, app delete) behalten
Schlüssel und Webhooks synchron.
Fehlerbehebung
| Symptom | Wahrscheinliche Ursache | Beheben |
|---|---|---|
| Webhook gibt 404 zurück | Agent noch nicht bereitgestellt | Lauf cipi deploy myapp nach dem Hinzufügen cipi/agent zu
composer.json
|
| Webhook gibt 403 / ungültige Signatur zurück | Geheimes Missverhältnis | Token erneut kopieren von cipi deploy myapp --webhook in die Providereinstellungen ein
|
| 200 OK, aber keine Bereitstellung | Branch wurde herausgefiltert | Überprüfen CIPI_DEPLOY_BRANCH entspricht dem gepushten Zweig |
| Bereitstellung hängt/Sperrfehler | Vorherige Bereitstellung unterbrochen | cipi deploy myapp --unlock Versuchen Sie es dann erneut |
| Deploy wird zweimal auf einmal ausgeführt | Webhook + Pipeline beide aktiv | Deaktivieren Sie einen Auslöser – siehe Übersicht |
deploy Werkzeug –
es nutzt das Gleiche .deploy-trigger Mechanismus. Siehe Cipi Agent
für Gesundheitschecks, MCP und Anonymisierungsfunktionen.CI/CD Pipelines – SSH-Bereitstellung
Wenn das Modell webhook nicht ausreicht, führen Sie es aus GitHub Aktionen oder GitLab
CI/CD Jobs, die per SSH auf den Server zugreifen und diese aufrufen cipi deploy. Das ist das
Die richtige Wahl, wann immer der Einsatz erfolgen muss bedingt – auf Tests beschränkt, denen Backups vorausgehen,
gefolgt von Benachrichtigungen oder der Orchestrierung neuer Vorschau-Apps.
Wenn Sie eine Pipeline anstelle eines webhook benötigen
- Qualitätstor – laufen
php artisan test, statische Analyse oder Frontend wird erstellt, bevor Code in Produktion geht - Sichere Freigabe — Snapshot der Datenbank und
shared/bis S3 vorher Tauschen des Symlinks (sicher bereitstellen) - Sichtbarkeit des Teams – Posten Sie Erfolg/Misserfolg an Slack oder Telegram mit aktiviertem Rollback Fehler (Benachrichtigungen bereitstellen)
- Überprüfen Sie Apps – Erstellen oder aktualisieren Sie eine vollständige Cipi-App pro Feature-Zweig (Vorschauumgebungen)
- Multi-App-Monorepo – bereitstellen
frontendundapiin parallel nach einem einzigen Testjob
Für diese Arbeitsabläufe gilt: Deaktivieren Sie die Produktion webhook (oder niemals eines erstellen) also nur Die Pipeline löst Bereitstellungen aus. Sie können weiterhin Cipi Agent in der App für Gesundheitsprüfungen und MCP verwenden.
SSH-Zugriff für CI
/root/.ssh/authorized_keys auf dem Server (bzw
cipi Benutzer, wenn Sie möchten sudo cipi deploy) und speichern Sie die
privater Schlüssel als CI-Geheimnis. Verwenden Sie Git-Bereitstellungsschlüssel oder persönliche SSH-Schlüssel niemals wieder.
# on your local machine $ ssh-keygen -t ed25519 -C "ci-deploy" -f ~/.ssh/ci_deploy -N "" # copy the public key to the server $ ssh-copy-id -i ~/.ssh/ci_deploy.pub root@your-server-ip # copy the private key content → add it as a CI secret (SERVER_SSH_KEY) $ cat ~/.ssh/ci_deploy
Speichern SERVER_HOST (Server-IP oder Hostname) daneben SERVER_SSH_KEY in deinem
Repository-Geheimnisse (GitHub) oder CI/CD Variablen (GitLab).
GitHub Aktionen – testen und dann bereitstellen
Fügen Sie den privaten Schlüssel als Repository-Geheimnis mit dem Namen hinzu SERVER_SSH_KEY und die Server-IP als
SERVER_HOST.
# .github/workflows/deploy.yml name: Deploy on: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run tests run: php artisan test deploy: runs-on: ubuntu-latest needs: test # only deploy if tests pass steps: - name: Deploy via Cipi uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: cipi key: ${{ secrets.SERVER_SSH_KEY }} script: sudo cipi deploy myapp
Für ein Rollback bei einem Fehler erweitern Sie den Skriptschritt:
script: |
sudo cipi deploy myapp || (sudo cipi deploy myapp --rollback && exit 1)
GitLab CI / CD
Fügen Sie den privaten Schlüssel als CI/CD-Variable mit dem Namen hinzu SERVER_SSH_KEY (Typ: Datei) und dem Server
IP als SERVER_HOST.
# .gitlab-ci.yml
stages:
- test
- deploy
test:
stage: test
script:
- php artisan test
deploy:
stage: deploy
environment: production
only:
- main
before_script:
- apt-get install -y openssh-client
- eval $(ssh-agent -s)
- echo "$SERVER_SSH_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- ssh-keyscan -H $SERVER_HOST >> ~/.ssh/known_hosts
script:
- ssh root@$SERVER_HOST "cipi deploy myapp"
Mit Rollback bei Fehler:
script:
- ssh root@$SERVER_HOST "cipi deploy myapp || (cipi deploy myapp --rollback && exit 1)"
Multi-App-Bereitstellung
Wenn dieselbe Pipeline mehrere Apps auf demselben Server verwaltet:
# GitHub Actions — deploy multiple apps in parallel
- name: Deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: root
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cipi deploy frontend &
cipi deploy api &
wait
Erweiterte Pipeline-Muster
Sobald die SSH-Bereitstellung funktioniert, fügen Sie diese Abschnitte zu einem einzigen Produktionsworkflow zusammen:
| Muster | Was die Pipeline hinzufügt | Leitfaden |
|---|---|---|
| Benachrichtigungen | Slack- oder Telegram-Nachricht bei Erfolg, Misserfolg und automatischem Rollback | Stellen Sie Benachrichtigungen bereit |
| Sichere Bereitstellung | cipi db backup + cipi backup run vor
cipi deploy; Rollback bei Fehler
|
Sichere Bereitstellung mit Backup |
| Vorschauumgebungen | Erstellen/Aktualisieren/Löschen pro Zweig Cipi Apps mit Platzhalter DNS + SSL | Vorschauumgebungen |
Ein typisches ausgereiftes Setup verwendet das webhook für eine Staging-App (sofortiges Feedback zu jedem drücken) und a Pipeline für die Produktion (Tests → Backup → Bereitstellen → Benachrichtigen). Jede App hat Es handelt sich um einen eigenen Auslöser – sie geraten nie in Konflikt, da sie auf unterschiedliche Cipi-App-Benutzer abzielen.
Stellen Sie Benachrichtigungen bereit
Pipeline-Anwendungsfall: Der Pfad webhook wird stillschweigend bereitgestellt – Git gibt 200 und das Team zurück
findet es nur heraus, wenn sie sich die Protokolle ansehen. Mit einem SSH-Pipeline, hinzufügen
Benachrichtigungsschritte danachcipi deploy um Erfolg, Misserfolg und Automatik zu übertragen
Rollbacks zu Slack oder Telegram. Beide Beispiele unten funktionieren mit GitHub-Aktionen und GitLab CI-Verwendung
nur standardmäßige HTTP-Aufrufe – keine zusätzlichen Plattformabhängigkeiten.
Locker
Fügen Sie einen letzten Schritt hinzu, der unabhängig vom Bereitstellungsergebnis in einem Slack webhook postet. Benutzen
if: always() in GitHub-Aktionen, sodass die Benachrichtigung sowohl bei Erfolg als auch bei Misserfolg ausgelöst wird.
Erstellen Sie eine Eingehend
Webhook in Ihrem Slack-Arbeitsbereich und speichern Sie die URL unter
SLACK_WEBHOOK_URL in Ihren CI-Geheimnissen.
# GitHub Actions — deploy + Slack notification
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
id: deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: root
key: ${{ secrets.SERVER_SSH_KEY }}
script: cipi deploy myapp
- name: Notify Slack — success
if: success()
uses: slackapi/slack-github-action@v2
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: |
{
"text": ":white_check_mark: *myapp* deployed successfully",
"attachments": [{
"color": "good",
"fields": [
{ "title": "Branch", "value": "${{ github.ref_name }}", "short": true },
{ "title": "By", "value": "${{ github.actor }}", "short": true },
{ "title": "Commit", "value": "${{ github.sha }}", "short": false }
]
}]
}
- name: Notify Slack — failure
if: failure()
uses: slackapi/slack-github-action@v2
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: |
{
"text": ":x: *myapp* deploy FAILED — rolling back",
"attachments": [{
"color": "danger",
"fields": [
{ "title": "Branch", "value": "${{ github.ref_name }}", "short": true },
{ "title": "By", "value": "${{ github.actor }}", "short": true },
{ "title": "Run", "value": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "short": false }
]
}]
}
- name: Rollback on failure
if: failure()
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: root
key: ${{ secrets.SERVER_SSH_KEY }}
script: cipi deploy myapp --rollback
Verwenden Sie für GitLab CI curl direkt – kein Plugin erforderlich:
# .gitlab-ci.yml — deploy stage with Slack notification
deploy:
stage: deploy
script:
- ssh root@$SERVER_HOST "cipi deploy myapp" && export DEPLOY_STATUS="success" || export DEPLOY_STATUS="failed"
- |
if [ "$DEPLOY_STATUS" = "success" ]; then
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"text\":\":white_check_mark: *myapp* deployed by $GITLAB_USER_LOGIN on \`$CI_COMMIT_REF_NAME\`\"}"
else
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"text\":\":x: *myapp* deploy FAILED — <$CI_PIPELINE_URL|view pipeline>\"}"
ssh root@$SERVER_HOST "cipi deploy myapp --rollback"
exit 1
fi
Telegramm
Erstellen Sie einen Telegram-Bot über @BotFather, holen Sie sich das Bot-Token und suchen Sie Ihre Chat-/Gruppen-ID.
Speichern Sie sie als TELEGRAM_BOT_TOKEN und TELEGRAM_CHAT_ID in CI-Geheimnissen.
# GitHub Actions — deploy + Telegram notification
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
id: deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: root
key: ${{ secrets.SERVER_SSH_KEY }}
script: cipi deploy myapp
- name: Notify Telegram — success
if: success()
run: |
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
-d parse_mode="Markdown" \
-d text="✅ *myapp* deployed successfully%0ABranch: \`${{ github.ref_name }}\`%0ABy: ${{ github.actor }}"
- name: Notify Telegram — failure + rollback
if: failure()
run: |
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
-d parse_mode="Markdown" \
-d text="❌ *myapp* deploy FAILED — rolling back%0ABranch: \`${{ github.ref_name }}\`%0A[View run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
ssh -o StrictHostKeyChecking=no -i <(echo "${{ secrets.SERVER_SSH_KEY }}") \
root@${{ secrets.SERVER_HOST }} "cipi deploy myapp --rollback"
GitLab CI-Äquivalent (rein). curl, keine zusätzlichen Abhängigkeiten):
# .gitlab-ci.yml — deploy stage with Telegram notification
deploy:
stage: deploy
script:
- ssh root@$SERVER_HOST "cipi deploy myapp" && RESULT="✅ deployed" || RESULT="❌ FAILED"
- |
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="$TELEGRAM_CHAT_ID" \
-d parse_mode="Markdown" \
-d text="*myapp* ${RESULT}%0ABranch: \`$CI_COMMIT_REF_NAME\`%0ABy: $GITLAB_USER_LOGIN"
- |
if echo "$RESULT" | grep -q "FAILED"; then
ssh root@$SERVER_HOST "cipi deploy myapp --rollback"
exit 1
fi
https://api.telegram.org/bot<TOKEN>/getUpdates und suche nach dem
chat.id Feld in der Antwort. Für private Chats schreiben Sie einfach zuerst eine Nachricht an den Bot.
Sichere Bereitstellung – Sicherung vor der Veröffentlichung
Für einen integrierten Dump unmittelbar vor der Ausführung des Deployers (keine Pipeline-Phase erforderlich) verwenden Sie
--snapshot / --snapshot-requiredoder aktivieren cipi app edit <app> --predeploy-snapshot.
Pipeline-Anwendungsfall: Eine webhook-Bereitstellung kann vor der Codefreigabe keinen Sicherungsschritt ausführen –
Das Push-Ereignis wird sofort bereitgestellt. In einem CI/CD-Pipeline, füge a hinzu
gewidmet backup Phase, die vorher gelingen muss deploy beginnt. A
Ein produktionstauglicher Workflow sollte immer einen Wiederherstellungspunkt erstellen vor Der neue Code geht
leben. Cipi bietet zwei komplementäre Sicherungsbefehle, die zwei verschiedenen Sicherheitsstufen zugeordnet sind:
# local DB snapshot — fast, on-disk, instant rollback $ cipi db backup myapp # → /var/log/cipi/backups/myapp_20260303_143012.sql.gz # S3 backup — DB dump + shared/ folder uploaded to your bucket $ cipi backup run myapp # → s3://your-bucket/cipi/myapp/2026-03-03_143015/db.sql.gz # → s3://your-bucket/cipi/myapp/2026-03-03_143015/shared.tar.gz
Wenn sie zusammen in einer Pipeline verwendet werden, erhalten Sie sowohl einen schnellen lokalen Wiederherstellungspunkt als auch eine Off-Server-Kopie davon die Datenbank und alle hochgeladenen Dateien. Die Bereitstellung beginnt nur, wenn beide Sicherungen erfolgreich sind.
cipi backup configure einmal auf dem Server zu
Verknüpfen Sie zuvor Ihre S3-Anmeldeinformationen cipi backup run verwendet werden kann.
cipi db backup funktioniert ohne jegliche Konfiguration – es ist immer verfügbar.
Was jeder Befehl intern bewirkt
cipi db backup <app> Anrufe
mysqldump --single-transaction --routines --triggers und komprimiert die Ausgabe in gzip
/var/log/cipi/backups/<app>_<timestamp>.sql.gz. Die Datei bleibt auf dem
Server und wird nie automatisch gelöscht – fügen Sie einen Bereinigungsschritt oder einen cron hinzu, wenn der Speicherplatz wichtig ist.
cipi backup run <app> macht zwei Dinge: Dump der Datenbank mit
mariadb-dump --single-transaction in ein temporäres Verzeichnis und archiviert das Ganze
/home/<app>/shared/ Ordner (der enthält .env,
storage/und alle vom Benutzer hochgeladenen Dateien). Beide Archive werden dann unter S3 hochgeladen
Pfad cipi/<app>/<timestamp>/. Nach erfolgreichem Abschluss werden die temporären Dateien gelöscht
hochladen.
GitHub Aktionen – sicherer Bereitstellungsworkflow
# .github/workflows/deploy.yml name: Deploy on: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: php artisan test backup: runs-on: ubuntu-latest needs: test steps: - name: Local DB backup uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: cipi db backup myapp - name: S3 backup (DB + shared) uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: cipi backup run myapp deploy: runs-on: ubuntu-latest needs: backup # only runs if backup job succeeds steps: - name: Deploy uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: cipi deploy myapp - name: Rollback on failure if: failure() uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: | cipi deploy myapp --rollback echo "Deploy failed — rolled back to previous release"
Das Jobdiagramm erzwingt die Reihenfolge: test → backup → deploy. Wenn
Wenn ein Auftrag fehlschlägt, werden die nachfolgenden übersprungen. Wenn der Bereitstellungsschritt selbst fehlschlägt, wird der
rollback Schritt wird automatisch ausgelöst und stellt die vorherige Deployer-Version wieder her.
GitLab CI/CD – sichere Bereitstellungspipeline
# .gitlab-ci.yml
stages:
- test
- backup
- deploy
variables:
APP: myapp
.ssh: &ssh
before_script:
- apt-get install -y openssh-client
- eval $(ssh-agent -s)
- echo "$SERVER_SSH_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- ssh-keyscan -H "$SERVER_HOST" >> ~/.ssh/known_hosts
test:
stage: test
script: php artisan test
only: [main]
backup-local:
stage: backup
<<: *ssh
only: [main]
script:
- ssh root@$SERVER_HOST "cipi db backup $APP"
backup-s3:
stage: backup
<<: *ssh
only: [main]
script:
- ssh root@$SERVER_HOST "cipi backup run $APP"
deploy:
stage: deploy
<<: *ssh
only: [main]
script:
- |
ssh root@$SERVER_HOST "
cipi deploy $APP || {
cipi deploy $APP --rollback
echo 'Deploy failed — rolled back'
exit 1
}
"
after_script:
- echo "Released → https://myapp.com"
backup-local und backup-s3 befinden sich in der gleichen Phase und laufen daher parallel, wenn
Sie haben mehrere Läufer, was die gesamte Pipeline-Zeit verkürzt. Beides muss vor dem Erfolg gelingen
deploy Etappe beginnt.
Wiederherstellung aus lokaler Sicherung
Wenn Sie die Datenbank auf den Snapshot zurücksetzen müssen, der unmittelbar vor der Bereitstellung erstellt wurde:
# list available local snapshots $ ls -lh /var/log/cipi/backups/myapp_*.sql.gz # restore the most recent one $ cipi db restore myapp /var/log/cipi/backups/myapp_20260303_143012.sql.gz # also roll back the code release $ cipi deploy myapp --rollback
Wiederherstellung aus S3-Backup
# list available S3 snapshots for this app $ cipi backup list myapp # download the DB snapshot from S3 $ aws s3 cp s3://your-bucket/cipi/myapp/2026-03-03_143015/db.sql.gz /tmp/db.sql.gz # restore the database $ cipi db restore myapp /tmp/db.sql.gz # (optional) restore shared/ files $ aws s3 cp s3://your-bucket/cipi/myapp/2026-03-03_143015/shared.tar.gz /tmp/shared.tar.gz $ tar -xzf /tmp/shared.tar.gz -C /home/myapp/
.sql.gz Datei an /var/log/cipi/backups/. Bei einem vollen Einsatzplan
Fügen Sie eine Bereinigung cron hinzu oder behalten Sie nur die letzten N Dateien:ls -t /var/log/cipi/backups/myapp_*.sql.gz | tail -n +6 | xargs rm -fIn diesem Beispiel werden die fünf aktuellsten Snapshots beibehalten und ältere gelöscht.
Vorschauumgebungen (Bereitstellung pro Zweig)
Pipeline-Anwendungsfall: Webhooks verweisen auf eine einzelne Produktions-URL – sie können keine erstellen
neue Cipi App pro Zweig. Vorschauumgebungen erfordern a CI/CD
Pipeline dass eine SSH-Verbindung zum Server hergestellt wird, ein deterministischer App-Name aus dem Zweig berechnet wird und
läuft cipi app create oder cipi deploy entsprechend. Jede Nichtproduktion
Zweig kann seine eigene Live-URL erhalten – eine vollständig bereitgestellte Laravel-App mit eigener Datenbank, eigenen Workern und
HTTPS. Dieses Muster wird manchmal als „Rezensions-Apps“ oder „ephemere Umgebungen“ bezeichnet.
Das URL-Format verwendet drei durch Bindestriche getrennte Slugs, sodass jede Umgebung für Menschen lesbar ist Weltweit einzigartig:
https://develop-acmeco-3a1f9c2e.preview.domain.ltd https://release-1-2-3-acmeco-3a1f9c2e.preview.domain.ltd https://main-acmeco-3a1f9c2e.preview.domain.ltd
Wie die Bezeichner generiert werden
Zur Pipeline-Laufzeit werden drei Werte abgeleitet:
# branch name → lowercase, non-alphanum → hyphens, trim edges BRANCH_SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//') # repo/project name → same treatment PROJECT_SLUG=$(echo "$PROJECT" | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g') # deterministic MD5 hash — same branch always gets the same environment HASH=$(echo -n "${BRANCH_SLUG}${PROJECT_SLUG}" | md5sum | cut -c1-8) # Cipi app username: must be lowercase alphanumeric, 3–32 chars, no hyphens # hex chars (0–9, a–f) are valid; prefix "pr" ensures it starts with a letter APP_NAME="pr${HASH}" # e.g. pr3a1f9c2e # human-readable domain with wildcard base DOMAIN="${BRANCH_SLUG}-${PROJECT_SLUG}-${HASH}.${DEPLOY_WILDCARD_DOMAIN}"
Voraussetzungen (einmalige Servereinrichtung)
A aufzeichnen
*.preview.domain.ltd → <server-ip> bei Ihrem DNS-Anbieter. Alle Subdomains
automatisch auflösen; Es sind keine DNS-Änderungen pro Zweig erforderlich.2. Wildcard-Zertifikat SSL – Erhalten Sie einmal ein Wildcard-Zertifikat über die DNS-01-Herausforderung und installieren Sie es auf dem Server. Siehe die Wildcard-Domains Abschnitt für Anweisungen. Der Zertifikatspfad wird von den folgenden Pipeline-Beispielen verwendet
/etc/letsencrypt/live/preview.domain.ltd/.3. Repository-Zugriff – Die Pipeline-Beispiele verwenden eine HTTPS-URL mit einem persönlichen Das Zugriffstoken (PAT) ist eingebettet, sodass kein SSH-Bereitstellungsschlüssel pro App eingerichtet werden muss. Der Token benötigt nur lesen Zugriff auf das Repository.
GitHub Aktionen
Fügen Sie diese Geheimnisse zum Repository hinzu: SERVER_HOST, SERVER_SSH_KEY,
DEPLOY_WILDCARD_DOMAIN (z.B. preview.domain.ltd), GH_PAT (a
feinkörniges PAT mit Lesezugriff auf das Repo).
# .github/workflows/preview.yml name: Preview on: push: branches-ignore: [main, master] # main branch uses your production pipeline delete: # clean up when a branch is deleted jobs: deploy: if: github.event_name == 'push' runs-on: ubuntu-latest steps: - name: Compute identifiers id: ids run: | BRANCH_SLUG=$(echo "${{ github.ref_name }}" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//') PROJECT_SLUG=$(echo "${{ github.event.repository.name }}" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g') HASH=$(echo -n "${BRANCH_SLUG}${PROJECT_SLUG}" | md5sum | cut -c1-8) APP_NAME="pr${HASH}" DOMAIN="${BRANCH_SLUG}-${PROJECT_SLUG}-${HASH}.${{ secrets.DEPLOY_WILDCARD_DOMAIN }}" REPO="https://oauth2:${{ secrets.GH_PAT }}@github.com/${{ github.repository }}.git" echo "app_name=${APP_NAME}" >> "$GITHUB_OUTPUT" echo "domain=${DOMAIN}" >> "$GITHUB_OUTPUT" echo "repo_url=${REPO}" >> "$GITHUB_OUTPUT" - name: Create or update preview uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: | APP="${{ steps.ids.outputs.app_name }}" DOMAIN="${{ steps.ids.outputs.domain }}" REPO="${{ steps.ids.outputs.repo_url }}" BRANCH="${{ github.ref_name }}" WILDCARD="/etc/letsencrypt/live/${{ secrets.DEPLOY_WILDCARD_DOMAIN }}" if cipi app show "$APP" &>/dev/null; then echo "→ Updating: $APP" cipi deploy "$APP" else echo "→ Creating: $APP → $DOMAIN" cipi app create \ --user="$APP" \ --domain="$DOMAIN" \ --repository="$REPO" \ --branch="$BRANCH" \ --php=8.5 # Patch nginx to listen on 443 using the pre-installed wildcard cert awk -v cert="$WILDCARD" ' /^ listen 80;/ { print print " listen 443 ssl http2;" print " ssl_certificate " cert "/fullchain.pem;" print " ssl_certificate_key " cert "/privkey.pem;" next } { print } ' "/etc/nginx/sites-available/$APP" > /tmp/_cipi_vhost \ && mv /tmp/_cipi_vhost "/etc/nginx/sites-available/$APP" nginx -t && systemctl reload nginx cipi deploy "$APP" fi - name: Print preview URL run: | echo "" echo " Preview → https://${{ steps.ids.outputs.domain }}" echo "" cleanup: if: github.event_name == 'delete' runs-on: ubuntu-latest steps: - name: Compute identifiers id: ids run: | BRANCH_SLUG=$(echo "${{ github.event.ref }}" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//') PROJECT_SLUG=$(echo "${{ github.event.repository.name }}" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g') HASH=$(echo -n "${BRANCH_SLUG}${PROJECT_SLUG}" | md5sum | cut -c1-8) echo "app_name=pr${HASH}" >> "$GITHUB_OUTPUT" - name: Delete preview uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: | APP="${{ steps.ids.outputs.app_name }}" if cipi app show "$APP" &>/dev/null; then echo "y" | cipi app delete "$APP" echo "→ Deleted: $APP" else echo "→ Not found, nothing to delete" fi
GitLab CI/CD
Fügen Sie diese CI/CD-Variablen hinzu: SERVER_HOST, SERVER_SSH_KEY (Dateityp),
DEPLOY_WILDCARD_DOMAIN, GL_TOKEN (ein Projekt-/Gruppenzugriffstoken mit
read_repository Geltungsbereich).
# .gitlab-ci.yml stages: - preview - cleanup .ssh_setup: &ssh_setup before_script: - apt-get install -y openssh-client - eval $(ssh-agent -s) - echo "$SERVER_SSH_KEY" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh - ssh-keyscan -H "$SERVER_HOST" >> ~/.ssh/known_hosts .compute_ids: &compute_ids | BRANCH_SLUG=$(echo "$CI_COMMIT_REF_NAME" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//') PROJECT_SLUG=$(echo "$CI_PROJECT_NAME" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g') HASH=$(echo -n "${BRANCH_SLUG}${PROJECT_SLUG}" | md5sum | cut -c1-8) APP="pr${HASH}" DOMAIN="${BRANCH_SLUG}-${PROJECT_SLUG}-${HASH}.${DEPLOY_WILDCARD_DOMAIN}" REPO="https://oauth2:${GL_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" WILDCARD="/etc/letsencrypt/live/${DEPLOY_WILDCARD_DOMAIN}" deploy-preview: stage: preview <<: *ssh_setup except: - main - master script: - *compute_ids - | ssh root@$SERVER_HOST bash -s << ENDSSH APP="$APP" DOMAIN="$DOMAIN" REPO="$REPO" BRANCH="$CI_COMMIT_REF_NAME" WILDCARD="$WILDCARD" if cipi app show "\$APP" &>/dev/null; then echo "Updating: \$APP" cipi deploy "\$APP" else echo "Creating: \$APP → \$DOMAIN" cipi app create \ --user="\$APP" \ --domain="\$DOMAIN" \ --repository="\$REPO" \ --branch="\$BRANCH" \ --php=8.5 awk -v cert="\$WILDCARD" ' /^ listen 80;/ { print print " listen 443 ssl http2;" print " ssl_certificate " cert "/fullchain.pem;" print " ssl_certificate_key " cert "/privkey.pem;" next } { print } ' "/etc/nginx/sites-available/\$APP" > /tmp/_cipi_vhost \ && mv /tmp/_cipi_vhost "/etc/nginx/sites-available/\$APP" nginx -t && systemctl reload nginx cipi deploy "\$APP" fi ENDSSH - echo "Preview → https://$DOMAIN" cleanup-preview: stage: cleanup <<: *ssh_setup only: - branches when: manual # or trigger on MR merge via rules: script: - *compute_ids - | ssh root@$SERVER_HOST " APP='$APP' if cipi app show \"\$APP\" &>/dev/null; then echo 'y' | cipi app delete \"\$APP\" fi "
cleanup-preview automatisch, wenn eine Zusammenführungsanforderung vorliegt
durch Hinzufügen von a zusammengeführt rules: Block, der prüft
$CI_MERGE_REQUEST_EVENT_TYPE == "merge_train" oder mit einem dedizierten
workflow: mit if: $CI_PIPELINE_SOURCE == "merge_request_event".
Hinweise und Grenzen
cipi app list regelmäßig überprüfen und veraltete Vorschauen löschen.Der Patch nginx SSL ist nicht idempotent – wenn die Pipeline läuft
cipi app create zweimal (z. B. aufgrund eines Wiederholungsversuchs), die awk Patch wird sein
erneut angewendet. Der Hash sorgt dafür APP_NAME ist deterministisch, also die
if cipi app show Der Schutz verhindert unter normalen Bedingungen eine Doppelerstellung.Vermeiden Sie Laufen
cipi ssl install in einer Vorschau-App – das wird es
Überschreiben Sie die Wildcard-Zertifikatkonfiguration mit einem domänenspezifischen Let's Encrypt-Zertifikat, das fehlschlägt (das
Die Domain hat keinen dedizierten DNS-Eintrag, nur den Platzhalter.