Déployer et CI/CD
cipi deploy
Cipi utilise Déployeur pour tous les déploiements. Chaque déploiement est atomique : une nouvelle version
répertoire est entièrement préparé avant le current le lien symbolique est échangé, donc le trafic n'est jamais
interrompu.
cipi deploy et cipi deploy --rollback
abandonner avec un message de mise à niveau clair avant appeler Deployer lorsqu'une application est toujours épinglée
vers une ancienne version PHP – changez-la avec cipi app edit <app> --php=8.3 (ou
supérieur) en premier.Déployer un pipeline
Deployer et Composer s'exécutent avec le version PHP configurée de l'application (par ex.
/usr/bin/php8.5), et non la valeur par défaut du système. Ceci s'applique à cipi deploy,
cipi deploy --rollback, crontab déploie des déclencheurs, cipi sync import déploie,
et le deploy / composeralias dans l'utilisateur de l'application .bashrc.
- Arrêter les travailleurs de file d'attente (
cipi worker stop) - Cloner le dépôt dans
releases/N/ - Courir
composer install --no-dev(avec PHP de l'application) - Lien
shared/.envetshared/storage/ - Courir
artisan migrate --force - Courir
artisan optimize - Courir
artisan storage:link - Échange
currentlien symbolique atomiquement - Redémarrer les travailleurs de file d'attente
- Élaguez les anciennes versions (conservez les 5 dernières)
$ 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)
Depuis v5.0, s'inscrire pré-déployer des instantanés de base de données sont disponibles via
--snapshot / --snapshot-required ou un paramètre d'application permanent - voir
Pré-déployer des instantanés de base de données. Octane applications utilisent le
laravel-octane.php Modèle de déploiement (recharger/redémarrer Octane lors du déploiement) ; activer le nœud
construit avec cipi app edit <app> --node-build='…'.
cipi deploy myapp --unlock pour le supprimer avant de le redéployer.Pré-déployer des instantanés de base de données
Depuis v5.0, cipi deploy <app> peut vider la base de données
avant le pipeline de publication s'exécute. Les instantanés atterrissent sous
/var/log/cipi/backups/ — le même chemin utilisé par
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
Que se passe-t-il
- Avant le démarrage du déploiement, Cipi effectue un dump de base de données dans
/var/log/cipi/backups/. - Avec
--snapshot-required, un dump échoué (ou un moteur de base de données manquant) blocs le déploiement. - Avec
--snapshotseul, un dump échoué imprime un avertissement et le déploiement continue.
Activer à chaque déploiement
Activez-le de manière permanente pour une application afin que chaque déploiement (CLI, webhook ou pipeline) prenne d'abord un instantané :
$ cipi app edit shop --predeploy-snapshot
cipi deploy --rollback restaure le précédent coder libération seulement.
C'est le cas pas restaurer la base de données. Si vous avez besoin du dump de pré-déploiement, utilisez
cipi db restore.Pour les workflows de pipeline qui archivent également shared/ à S3 avant la sortie, voir
Déploiement sécurisé : sauvegarde avant la publication.
cipi app deploy-config
Depuis v5.0.3, gérez les options de recettes de déploiement durables stockées dans
apps.json et appliqué en régénérant deploy.php à partir du modèle -
une alternative sûre à l'édition de PHP de forme libre.
$ 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
REPOS : GET|PUT /api/apps/{name}/deploy-config (capacité
apps-deploy-config, API 1.14+ / Cipi 5.0.3+).
MCP : AppDeployConfigShow, AppDeployConfigUpdate.
auth.json
Gérer le auth.json fichier pour une application. Ce fichier se trouve à
/home/<app>/shared/auth.json et est automatiquement lié symboliquement à chaque version par
Déployeur - exactement comme .env. Utilisez-le pour stocker des données d'identification structurées (par exemple API
clés, indicateurs de fonctionnalité ou toute charge utile JSON) que votre application Laravel peut lire au moment de l'exécution.
$ 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
REPOS : GET|POST|PUT|DELETE /api/apps/{name}/auth (capacité apps-auth, API
1.14+) — Composer/structuré JSON, distinct de HTTP Basic Auth.
MCP : AppAuthJsonShow, AppAuthJsonCreate,
AppAuthJsonUpdate, AppAuthJsonDelete.
Détails de la commande
| Commande | Descriptif |
|---|---|
cipi auth create <app> |
Crée shared/auth.json avec la structure initiale
{"users":[]}, définit les autorisations sur 640 (propriétaire
app:app), et ajoute auth.json à
shared_files dans la configuration du déploiement de l'application afin qu'il soit lié symboliquement à chaque
déployer.
|
cipi auth edit <app> |
Ouvre shared/auth.json dans $EDITOR (retombe à
nano). Après la fermeture de l'éditeur, valide le JSON avec
jq et avertit si le fichier est mal formé.
|
cipi auth show <app> |
Imprime le contenu de shared/auth.json formaté avec
jq.
|
cipi auth delete <app> |
Demande une confirmation, puis supprime shared/auth.json et supprime le
auth.json entrée de shared_files dans le déployeur de l'application
configuration.
|
Intégration du déployeur
cipi auth create ajoute automatiquement auth.json à la
shared_files liste dans /home/<app>/.deployer/deploy.php, et
cipi auth delete le supprime. Cela signifie que le fichier est traité exactement comme
.env: il persiste dans toutes les versions et n'est jamais écrasé par un déploiement.
cipi auth l'opération est enregistrée via log_action pour
auditabilité. Le AUTH La section est également répertoriée dans la sortie de
cipi help.
Fournisseurs Git
Cipi est prêt à travailler avec API et GitHub mais il prend en charge n'importe quel autre fournisseur Git qui prend en charge les clés de déploiement SSH – pas de dépendance vis-à-vis du fournisseur.
Pour self-hosted ou les serveurs Git personnalisés, vous devez faire confiance à l'empreinte digitale de l'hôte du serveur avant
Le déployeur peut cloner via SSH. Utilisez le --trust-host drapeau pour ajouter l'empreinte digitale au
utilisateur de l'application ~/.ssh/known_hosts automatiquement :
# 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 accès à l'utilisateur de l'application ~/.ssh/config donc
ce déployeur peut atteindre le serveur sans aucune configuration supplémentaire.
Configuration automatique de Git
Si vous enregistrez un API ou GitHub Jeton d'accès personnel, Cipi
ajoute automatiquement la clé de déploiement SSH et crée le webhook sur le référentiel à chaque fois que vous exécutezcipi app create. Aucune étape manuelle requise.
Enregistrer un jeton
# 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
Autorisations du jeton GitHub
Besoin de jetons à grain fin (recommandé) Administration et
Webhooks réglé sur Lire et écrire sur les référentiels cibles. Jetons classiques
besoin du repo portée.
Autorisations du jeton GitLab
Le api la portée est le minimum requis — GitLab n'offre pas une portée plus granulaire
qui couvre à la fois les clés de déploiement et les webhooks.
Cycle de vie automatique
| Événement | Ce que Cipi fait automatiquement |
|---|---|
app create |
Ajoute la clé de déploiement + crée webhook sur le référentiel via API. Le résumé montre "auto-configuré ✓" au lieu d'instructions manuelles. |
app edit --repository=... |
Supprime la clé de déploiement + webhook de l'ancien référentiel, puis les ajoute au nouveau. |
app delete |
Supprime la clé de déploiement + webhook du référentiel avant de supprimer l'application. |
cipi git commandes
| Commande | Descriptif |
|---|---|
cipi git status |
Afficher l'état de connexion du fournisseur et les détails d'intégration par application (ID de clé de déploiement, webhook ID) |
cipi git github-token <token> |
Enregistrez un jeton d'accès personnel GitHub |
cipi git gitlab-token <token> |
Enregistrez un jeton d'accès personnel GitLab |
cipi git gitlab-url <url> |
Définir l'URL de base pour une instance self-hosted GitLab |
cipi git remove-github |
Supprimez le jeton GitHub stocké |
cipi git remove-gitlab |
Supprimez le jeton GitLab et l'URL stockés |
Configuration manuelle (repli)
La configuration automatique est ignorée lorsqu'aucun jeton n'est configuré, lorsque l'appel API échoue (autorisations incorrectes, référentiel introuvable, limite de débit), ou lorsque le référentiel est hébergé chez un fournisseur autre que GitHub ou GitLab (par exemple Gitea, Forgejo, Bitbucket). Dans tous ces cas, Cipi revient au flux de travail manuel et la création de l'application se déroule normalement.
Pour configurer manuellement la clé de déploiement et webhook :
# 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
Ajoutez-les ensuite dans les paramètres du référentiel de votre fournisseur :
- Clé de déploiement — API : Paramètres → Clés de déploiement → Ajouter une clé de déploiement; GitLab : Paramètres → Référentiel → Clés de déploiement
- Webhook — API : Paramètres → Webhooks → Ajouter webhook;
API : Paramètres → Webhooks → Ajouter un nouveau webhook. Définissez l'URL de la charge utile et
secret des valeurs affichées par
cipi deploy myapp --webhook
Personnalisation du script de déploiement
La configuration de déploiement pour chaque application est stockée à :
Ce fichier est généré automatiquement par Cipi lors app create et mis à jour automatiquement lorsque vous
changez la version PHP ou déployez la branche via cipi app edit. Vous pouvez le modifier pour le personnaliser
le pipeline de déploiement, mais vous devez comprendre les implications avant de le faire.
Pipeline de déploiement par défaut
Le généré automatiquement deploy.php exécute ces tâches dans l'ordre :
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
Ajout de tâches personnalisées
Vous pouvez ajouter des tâches avant ou après n'importe quelle étape. Pour un exemple complet de build frontend (npm install && npm run build), voir
Création d'actifs front-end ci-dessous. Autres exemples courants :
// 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');
Création d'actifs frontend (npm / Vite)
Il n'y a pas de dédié cipi Indicateur CLI pour les builds frontend (par ex. npm install && npm run build).
Personnalisation deploy.php est l’approche soutenue et attendue — définir un
Déployeur task() et accroche-le avec after() ou before(). Vous ne le faites pas
il faut éviter cela ; l'extension du pipeline est exactement à quoi sert le fichier.
Cipi installations Node.js et npm sur le serveur lors de l'installation. Vérifiez qu'ils sont disponibles comme l'utilisateur de l'application :
$ ssh myapp@your-server-ip
myapp@server:~$ node -v && npm -v
S'engager package.json et package-lock.json à votre référentiel. Accrochez la construction
après deploy:shared donc .env est lié (Vite lit
VITE_* variables à partir de là) et avant deploy:symlink donc
Les ressources compilées existent dans la version avant sa mise en ligne.
Ajoutez le bloc ci-dessous à la en bas de
/home/myapp/.deployer/deploy.php, sous les définitions de tâches générées automatiquement par 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');
Cela équivaut à npm install && npm run build à chaque déploiement. Préférer
npm ci en production lorsque package-lock.json est engagé - c'est plus rapide et
reproductible. Utiliser npm install au lieu de cela seulement si vous ne verrouillez pas les dépendances.
Si vous avez besoin d'étapes d'installation et de construction distinctes (par exemple, pour mettre en cache node_modules à travers les versions),
divisez-les en deux tâches :
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');
Pour accélérer les déploiements ultérieurs, vous pouvez conserver les dépendances entre les versions en ajoutant
node_modules vers les répertoires partagés de Deployer (facultatif — uniquement si votre projet prend en charge
ça):
add('shared_dirs', ['node_modules']);
Modifiez le fichier sur le serveur en tant qu'utilisateur de l'application, puis testez avec 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 dans GitHub Actions
ou GitLab CI avant l'étape de déploiement SSH, de sorte que le serveur ne reçoit que des actifs prédéfinis.
Voir Pipelines CI/CD – Déploiement SSH.Exécution de commandes artisan supplémentaires
// 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 ou cipi app edit myapp --branch=X. Sauvegarder
vos personnalisations ou conservez-les dans une section clairement séparée des blocs gérés par Cipi. Un
le modèle sûr consiste à placer toutes les tâches personnalisées au bas du fichier après la tâche par défaut
définition.
Désactiver une étape par défaut
Pour ignorer une tâche (par exemple si vous gérez les migrations manuellement), commentez-la ou supprimez-la du
deploy définition de la tâche :
// 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', ]);
Tester vos modifications
Après édition deploy.php, effectuez toujours un test de déploiement avant de passer en production :
$ 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 ou via
cipi app logs myapp --type=deploy. Vérifiez-le d'abord lors du dépannage d'un échec
déployer.
Déployer et CI/CD – Présentation
Avec Cipi, CI (construire et tester) et CD (mise en production) peut
être divisés ou combinés. Chaque déploiement fonctionne finalement de la même manière Déployeur
canalisation sur le serveur — cloner, composer install, migrations, échange de liens symboliques,
redémarrage du travailleur. Quels sont les changements qu'est-ce qui déclenche ce pipeline.
Cipi prend en charge deux modèles de déclencheurs. Pour la plupart des applications Laravel, commencez par webhook + CipiAgent chemin. Passez à un pipeline CI/CD complet lorsque vous avez besoin de portes, de sauvegardes ou une orchestration d'infrastructure qu'un simple push hook ne peut pas exprimer.
Deux façons de déclencher un déploiement
| Webhook + Cipi Agent (recommandé) | Pipeline CI/CD via SSH | |
|---|---|---|
| Déclencheur | Le fournisseur Git POST vers /cipi/webhook en poussée |
GitHub Actions / GitLab exécutions de tâches CI cipi deploy via SSH |
| Accès au serveur depuis CI | Aucun – seulement HTTPS sur le domaine de votre application | Clé SSH dédiée stockée en tant que secret CI |
| Tests préalables au déploiement | Exécuter localement ou dans un travail CI distinct ; le déploiement se déclenche toujours en cas de poussée, sauf si vous désactivez le webhook | Natif : l'étape de déploiement ne s'exécute qu'après needs: test (ou équivalent) passe |
| Sauvegarde avant la sortie | Manuel ou cron sur le serveur | Travail de pipeline - voir déploiement sécurisé |
| Prévisualiser/examiner les applications | Non pris en charge dès la sortie de la boîte | Pipeline crée des applications Cipi par branche – voir aperçu environnements |
| Complexité de configuration | Faible — composer require cipi/agent + un webhook |
Moyen — Clé SSH, secrets, flux de travail YAML |
Quelle approche dois-je utiliser ?
| Cas d'utilisation | Approche recommandée | Où lire la suite |
|---|---|---|
Application unique Laravel, push-to-déploiement sur main |
Webhook + Agent | Configuration de Webhook |
| Déployer uniquement si les tests CI réussissent | Pipeline SSH (désactiver la production webhook) | Déploiement du pipeline SSH |
| Sauvegarde de base de données + fichiers avant chaque version de production | Pipeline SSH | Déploiement sécurisé avec sauvegarde |
| Alertes Slack / Telegram sur le résultat du déploiement | Pipeline SSH | Déployer les notifications |
| URL éphémère par branche de fonctionnalité (évaluer les applications) | Pipeline SSH | Environnements de prévisualisation |
| Déployer plusieurs applications sur un serveur à partir d'un seul dépôt | Soit — webhook par application, soit un pipeline avec parallèle cipi deploy |
Déploiement multi-applications |
cipi deploy myapp --unlock si un cadenas coincé est laissé sur place.
Déploiements automatiques : agent Cipi et webhook
cipi-agent (cipi/agent) est un package Laravel qui expose
POST /cipi/webhook dans votre application en cours d’exécution. Lorsque GitHub ou GitLab envoie un push
événement, l'agent valide la signature de la charge utile, en accuse réception immédiatement et met en file d'attente un déploiement sur
le serveur - pas de SSH du coureur CI, non sudo, aucun port entrant ouvert au-delà de HTTPS.
Comment fonctionne le flux webhook
Le design sépare accusé de réception rapide HTTP de Déployeur lent travail. Un déploiement peut prendre plusieurs minutes ; Les fournisseurs Git expirent les appels webhook HTTP après environ 10 secondes. Cipi résout ce problème avec un fichier d'indicateur et la crontab de l'utilisateur de l'application.
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 │
Le déployeur s'exécute toujours en tant que utilisateur de l'application Linux (par ex. myapp), avec le
corriger les autorisations PHP binaires et fichiers - le même contexte qu'un manuel
cipi deploy myapp. Le webhook ne s'adresse jamais directement au déployeur ; ça laisse seulement tomber le
fichier de déclenchement que la crontab de Cipi surveille déjà.
Conditions préalables
| Exigence | Pourquoi |
|---|---|
| Application Cipi créée avec le référentiel Git | La clé de déploiement doit cloner le dépôt - voir Configuration automatique de Git |
| Au moins un déploiement manuel réussi | Le package d'agent doit être présent dans le current version avant le webhook
l'itinéraire existe |
composer require cipi/agent dans le projet |
Enregistre le /cipi/webhook validation de l'itinéraire et de la signature |
| Webhook URL accessible sur HTTPS | Les fournisseurs Git nécessitent une URL publique ; utiliser cipi ssl install d'abord |
CIPI_WEBHOOK_TOKEN dans shared/.env |
Généré automatiquement à cipi app create; partagé dans toutes les versions |
Configuration étape par étape
1. Créez l'application et déployez-la une fois manuellement pour que le serveur puisse cloner votre dépôt :
$ cipi app create --user=myapp --domain=myapp.com \ --repository=git@github.com:you/myapp.git --branch=main --php=8.5 $ cipi deploy myapp
2. Installez l'agent Cipi dans votre projet Laravel localement, validez et poussez :
$ 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. Configurez le webhook. Si vous avez enregistré un jeton GitHub ou GitLab, Cipi peut avoir
déjà créé le webhook pendant app create — vérifier auprès de
cipi git status. Sinon, récupérez l'URL et le secret :
$ cipi deploy myapp --webhook
Ajoutez le webhook dans votre fournisseur Git :
| Fournisseur | URL de la charge utile | Champ secret | Événements |
|---|---|---|---|
| GitHub | https://myapp.com/cipi/webhook |
Secret → valeur de --webhook |
Juste le push événement |
| GitLab | https://myapp.com/cipi/webhook |
Jeton secret → même valeur | Événements push |
4. Restreindre à votre branche de déploiement (recommandé pour la production) :
CIPI_DEPLOY_BRANCH=main
Mettez ceci dans shared/.env via cipi app env myapp. Pousse vers d’autres branches
recevoir un skipped réponse et aucune exécution de déploiement.
5. Vérifiez. Envoyez un petit commit à main et regardez le journal de déploiement :
$ cipi app logs myapp --type=deploy # or on the server as the app user: $ tail -f /home/myapp/logs/deploy.log
Environ une minute après la livraison de webhook, une nouvelle version de Deployer devrait apparaître. Confirmez le
commit en direct avec php artisan cipi:status ou le santé
vérifier point final.
Configuration automatique de Git
Quand un Jeton GitHub ou GitLab est configuré sur le serveur, Cipi
enregistre la clé de déploiement et crée automatiquement le webhook à chaque
cipi app create. Le résumé de l'application affiche "auto-configuré ✓" au lieu du manuel
instructions. Événements du cycle de vie (app edit --repository, app delete) garder
clés et webhooks synchronisés.
Dépannage
| Symptôme | Cause probable | Corriger |
|---|---|---|
| Webhook renvoie 404 | Agent pas encore déployé | Courir cipi deploy myapp après avoir ajouté cipi/agent à
composer.json
|
| Webhook renvoie 403 / signature invalide | Inadéquation secrète | Recopier le jeton de cipi deploy myapp --webhook dans les paramètres du fournisseur
|
| 200 OK mais pas de déploiement | Branche filtrée | Vérifier CIPI_DEPLOY_BRANCH correspond à la branche poussée |
| Déploiement bloqué/erreur de verrouillage | Déploiement précédent interrompu | cipi deploy myapp --unlock puis réessaye |
| Le déploiement s'exécute deux fois en une seule fois | Webhook + pipeline tous deux actifs | Désactivez un déclencheur - voir aperçu |
deploy outil —
il utilise la même chose .deploy-trigger mécanisme. Voir CipiAgent
pour les contrôles de santé, MCP et les fonctionnalités d'anonymisation.Pipelines CI/CD – Déploiement SSH
Lorsque le modèle webhook ne suffit pas, exécutez GitHub Actions ou GitLab
CI/CD tâches qui se connectent en SSH au serveur et invoquent cipi deploy. C'est le
le bon choix chaque fois que le déploiement doit être conditionnel — gated sur tests, précédés de sauvegardes,
suivi de notifications ou orchestrer de nouvelles applications en avant-première.
Quand vous avez besoin d'un pipeline au lieu d'un webhook
- Porte de qualité — courir
php artisan test, analyse statique ou frontend construit avant qu'un code n'atteigne la production - Libération en toute sécurité — instantané de la base de données et
shared/à S3 avant échanger le lien symbolique (déploiement sécurisé) - Visibilité de l'équipe - publier le succès/l'échec sur Slack ou Telegram avec restauration activée échec (déployer des notifications)
- Examiner les applications — créer ou mettre à jour une application Cipi complète par branche de fonctionnalités (environnements de prévisualisation)
- Monorepo multi-applications — déployer
frontendetapidans parallèle après un seul travail de test
Pour ces flux de travail, désactiver la production webhook (ou ne jamais en créer un) donc seulement le pipeline déclenche le déploiement. Vous pouvez toujours utiliser l'agent Cipi dans l'application pour les contrôles de santé et MCP.
Accès SSH pour CI
/root/.ssh/authorized_keys sur le serveur (ou le
cipi utilisateur si vous préférez sudo cipi deploy) et stockez le
clé privée comme un secret CI. Ne réutilisez jamais les clés de déploiement Git ou les clés SSH personnelles.
# 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
Magasin SERVER_HOST (IP du serveur ou nom d'hôte) à côté SERVER_SSH_KEY dans votre
secrets du référentiel (GitHub) ou variables CI/CD (GitLab).
GitHub Actions : tester puis déployer
Ajoutez la clé privée en tant que secret du référentiel nommé SERVER_SSH_KEY et l'IP du serveur comme
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
Pour une restauration en cas d'échec, étendez l'action de script :
script: |
sudo cipi deploy myapp || (sudo cipi deploy myapp --rollback && exit 1)
GitLab CI/CD
Ajoutez la clé privée en tant que variable CI/CD nommée SERVER_SSH_KEY (tapez : Fichier) et le serveur
IP comme 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"
Avec rollback en cas d'échec :
script:
- ssh root@$SERVER_HOST "cipi deploy myapp || (cipi deploy myapp --rollback && exit 1)"
Déploiement multi-applications
Si le même pipeline gère plusieurs applications sur le même serveur :
# 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
Modèles de pipeline avancés
Une fois le déploiement SSH fonctionnel, composez ces sections en un seul workflow de production :
| Modèle | Ce que le pipeline ajoute | Guider |
|---|---|---|
| Notifications | Message Slack ou Telegram sur le succès, l'échec et la restauration automatique | Déployer les notifications |
| Déploiement sécurisé | cipi db backup + cipi backup run avant
cipi deploy; restauration en cas d'échec
|
Déploiement sécurisé avec sauvegarde |
| Environnements de prévisualisation | Créer/mettre à jour/supprimer des applications Cipi par branche avec le caractère générique DNS + SSL | Environnements de prévisualisation |
Une configuration mature typique utilise le webhook pour une application de mise en scène (retour instantané sur chaque pousser) et un canalisation pour la production (tests → sauvegarde → déployer → notifier). Chaque application a son propre déclencheur : ils ne sont jamais en conflit car ils ciblent différents utilisateurs de l'application Cipi.
Déployer les notifications
Cas d'utilisation du pipeline : le chemin webhook se déploie silencieusement — Git renvoie 200 et l'équipe
ne le découvre que s'ils regardent les journaux. Avec un Pipeline SSH, ajouter
étapes de notification aprèscipi deploy pour diffuser le succès, l'échec et l'automatique
retours vers Slack ou Telegram. Les deux exemples ci-dessous fonctionnent avec GitHub Actions et GitLab CI en utilisant
uniquement les appels HTTP standard — pas de dépendances de plate-forme supplémentaires.
Mou
Ajoutez une étape finale qui publie sur un Slack webhook quel que soit le résultat du déploiement. Utiliser
if: always() dans GitHub Actions afin que la notification se déclenche à la fois en cas de succès et d'échec.
Créer un Entrant
Webhook dans votre espace de travail Slack et stockez l'URL sous
SLACK_WEBHOOK_URL dans vos secrets CI.
# 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
Pour GitLab CI, utilisez curl directement — aucun plugin n'est nécessaire :
# .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
Télégramme
Créez un bot Telegram via @BotPère, récupérez le jeton du bot et trouvez votre identifiant de discussion/groupe.
Conservez-les comme TELEGRAM_BOT_TOKEN et TELEGRAM_CHAT_ID dans les secrets de CI.
# 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 Équivalent CI (pur curl, pas de dépendances supplémentaires) :
# .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 et cherche le
chat.id champ dans la réponse. Pour les discussions privées, envoyez d’abord un message au bot.
Déploiement sécurisé : sauvegarde avant la publication
Pour un vidage intégré juste avant l'exécution de Deployer (aucune étape de pipeline requise), utilisez
--snapshot / --snapshot-requiredou activer cipi app edit <app> --predeploy-snapshot.
Cas d'utilisation du pipeline : un déploiement webhook ne peut pas exécuter une étape de sauvegarde avant de publier le code -
l'événement push se déclenche immédiatement. Dans un CI/CD pipeline, ajoutez un
dédié backup étape qui doit réussir avant deploy démarre. Un
le flux de travail de qualité production doit toujours créer un point de restauration avant le nouveau code va
vivre. Cipi fournit deux commandes de sauvegarde complémentaires qui correspondent à deux niveaux de sécurité différents :
# 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
Utilisés ensemble dans un pipeline, ils vous offrent à la fois un point de restauration local rapide et une copie hors serveur de la base de données et tous les fichiers téléchargés. Le déploiement ne démarre que si les deux sauvegardes réussissent.
cipi backup configure une fois sur le serveur pour
associez vos identifiants S3 avant cipi backup run peut être utilisé.
cipi db backup fonctionne sans aucune configuration — il est toujours disponible.
Ce que fait chaque commande en interne
cipi db backup <app> appels
mysqldump --single-transaction --routines --triggers et compresse la sortie dans
/var/log/cipi/backups/<app>_<timestamp>.sql.gz. Le fichier reste sur le
serveur et n'est jamais supprimé automatiquement - ajoutez une étape de nettoyage ou un cron si l'espace disque est important.
cipi backup run <app> fait deux choses : vide la base de données avec
mariadb-dump --single-transaction dans un répertoire temporaire et archive l'intégralité
/home/<app>/shared/ dossier (qui contient .env,
storage/, et tous les fichiers téléchargés par l'utilisateur). Les deux archives sont ensuite téléchargées vers S3 sous le
chemin cipi/<app>/<timestamp>/. Les fichiers temporaires sont supprimés après une réussite
télécharger.
GitHub Actions : flux de travail de déploiement sécurisé
# .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"
Le graphique de tâches applique l'ordre : test → backup → deploy. Si
toute tâche échoue, les suivantes sont ignorées. Si l'étape de déploiement elle-même échoue, le
rollback L’étape se déclenche automatiquement et restaure la version précédente de Deployer.
GitLab CI/CD — pipeline de déploiement sécurisé
# .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 et backup-s3 sont dans la même étape donc ils fonctionnent en parallèle si
vous disposez de plusieurs exécuteurs, ce qui réduit le temps global du pipeline. Les deux doivent réussir avant que
deploy l'étape commence.
Restaurer à partir d'une sauvegarde locale
Si vous devez restaurer la base de données vers l'instantané pris juste avant le déploiement :
# 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
Restaurer à partir de la sauvegarde S3
# 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 fichier à /var/log/cipi/backups/. Avec un calendrier de déploiement chargé,
ajoutez un nettoyage cron ou ne conservez que les N derniers fichiers :ls -t /var/log/cipi/backups/myapp_*.sql.gz | tail -n +6 | xargs rm -fCet exemple conserve les 5 instantanés les plus récents et supprime les plus anciens.
Environnements de prévisualisation (déploiement par branche)
Cas d'utilisation du pipeline : les webhooks pointent vers une seule URL de production – ils ne peuvent pas créer de
nouvelle application Cipi par branche. Les environnements de prévisualisation nécessitent un CI/CD
canalisation qui se connecte en SSH au serveur, calcule un nom d'application déterministe à partir de la branche et
court cipi app create ou cipi deploy par conséquent. Chaque non-production
La branche peut obtenir sa propre URL en direct - une application Laravel entièrement déployée avec sa propre base de données, ses propres travailleurs et
HTTPS. Ce modèle est parfois appelé « évaluer les applications » ou « environnements éphémères ».
Le format URL utilise trois slugs séparés par des tirets, afin que chaque environnement soit lisible par l'homme et unique au monde :
https://develop-acmeco-3a1f9c2e.preview.domain.ltd https://release-1-2-3-acmeco-3a1f9c2e.preview.domain.ltd https://main-acmeco-3a1f9c2e.preview.domain.ltd
Comment les identifiants sont générés
Trois valeurs sont dérivées lors de l'exécution du pipeline :
# 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}"
Prérequis (configuration unique du serveur)
A enregistrer
*.preview.domain.ltd → <server-ip> chez votre fournisseur DNS. Tous les sous-domaines
résoudre automatiquement ; aucune modification DNS par branche n'est nécessaire.2. Certificat générique SSL - obtenez un certificat générique via le défi DNS-01 une fois et installez-le sur le serveur. Voir le Domaines génériques section pour les instructions. Le chemin du certificat utilisé par les exemples de pipeline ci-dessous est
/etc/letsencrypt/live/preview.domain.ltd/.3. Accès au référentiel — les exemples de pipeline utilisent une URL HTTPS avec un nom personnel jeton d'accès (PAT) intégré, donc aucune configuration de clé de déploiement SSH par application n'est nécessaire. Le jeton n'a besoin que lire accès au référentiel.
GitHub Actions
Ajoutez ces secrets au référentiel : SERVER_HOST, SERVER_SSH_KEY,
DEPLOY_WILDCARD_DOMAIN (par ex. preview.domain.ltd), GH_PAT (un
PAT à granularité fine avec accès en lecture au dépôt).
# .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
Ajoutez ces variables CI/CD : SERVER_HOST, SERVER_SSH_KEY (Type de fichier),
DEPLOY_WILDCARD_DOMAIN, GL_TOKEN (un jeton d'accès au projet/groupe avec
read_repository portée).
# .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 automatiquement lorsqu'une demande de fusion est
fusionné en ajoutant un rules: bloc qui vérifie
$CI_MERGE_REQUEST_EVENT_TYPE == "merge_train" ou en utilisant un
workflow: avec if: $CI_PIPELINE_SOURCE == "merge_request_event".
Remarques et limites
cipi app list périodiquement et supprimez les aperçus obsolètes.Le patch nginx SSL n'est pas idempotent — si le pipeline fonctionne
cipi app create deux fois (par exemple suite à une nouvelle tentative), le awk le patch sera
appliqué à nouveau. Le hachage assure APP_NAME est déterministe, donc le
if cipi app show La protection empêche la double création dans des conditions normales.Évitez de courir
cipi ssl install sur une application de prévisualisation - ce sera
remplacer la configuration du certificat générique par un certificat Let's Encrypt par domaine qui échouera (le
le domaine n'a pas d'enregistrement DNS dédié, seulement le caractère générique).