- Restructuration VPS : guides rapide et complet séparés - Nouveau guide Vim essentiel pour administration serveur - Guide déploiement Kirby (VirtualHost, multi-sites, permissions) - Guide CI/CD Kirby (GitLab CI, Forgejo Actions, Docker) - Anonymisation complète (sécurité pour publication publique) - Priorité aux solutions libres (Forgejo, GitLab) - README général et navigation améliorée Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
23 KiB
CI/CD pour déployer Kirby
Automatiser le déploiement de Kirby CMS avec GitLab CI ou Forgejo Actions (alternatives libres).
🆓 Philosophie : Ce guide privilégie les solutions libres et open-source :
- Forgejo : Alternative libre à GitHub, auto-hébergeable
- GitLab : Solution mature avec version Community (libre)
- Pas de dépendance aux services propriétaires
📋 Table des matières
- Concepts de base
- GitLab CI (SSH/rsync)
- Forgejo Actions (SSH/rsync)
- Forgejo Actions (FTP)
- Image Docker optimisée
- Configuration des secrets
- Troubleshooting
Concepts de base
Workflow typique
1. Push sur main/master
↓
2. CI/CD se déclenche
↓
3. Stage BUILD
- Installer les dépendances (Composer)
- Optimiser (autoloader, assets)
↓
4. Stage DEPLOY
- Se connecter au VPS (SSH ou FTP)
- Synchroniser les fichiers
- Exclure les dossiers sensibles (cache, sessions, accounts)
↓
5. ✅ Site déployé
Prérequis VPS
- VPS configuré → vps-setup-rapide.md
- Site Kirby fonctionnel → kirby-vps-deploy.md
- Clé SSH configurée (pour déploiement SSH)
GitLab CI (SSH/rsync)
Avantages
- ✅ Rapide (rsync ne transfère que les modifications)
- ✅ Sécurisé (SSH)
- ✅ Contrôle total (permissions, exclusions)
- ✅ Logs détaillés
Configuration complète
.gitlab-ci.yml à la racine du projet :
stages:
- build
- deploy
variables:
COMPOSER_ALLOW_SUPERUSER: "1"
# ===== STAGE BUILD =====
build_prod:
stage: build
only:
- main # Déclencher uniquement sur la branche main
image: composer:2 # Image officielle Composer
script:
# Installer les dépendances Kirby
- composer install --no-dev --optimize-autoloader --ignore-platform-req=ext-gd
artifacts:
# Fichiers à passer au stage deploy
paths:
- vendor/
- kirby/
- site/
- assets/
- content/
- media/
- index.php
- .htaccess
expire_in: 1 hour # Les artifacts expirent après 1h
# ===== STAGE DEPLOY =====
deploy_prod:
stage: deploy
image: alpine:latest
only:
- main
dependencies:
- build_prod # Récupère les artifacts du build
before_script:
# Installer rsync et SSH
- apk add --no-cache rsync openssh
# Configurer la clé SSH
- mkdir -p ~/.ssh
- echo -e "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
- chmod 600 ~/.ssh/id_ed25519
# Configuration SSH (désactiver la vérification de l'host)
- |
cat > ~/.ssh/config <<EOF
Host *
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
BatchMode yes
IdentitiesOnly yes
EOF
- chmod 600 ~/.ssh/config
script:
- echo "🚀 Déploiement sur le serveur de production..."
# Fonction rsync réutilisable
- |
rsync_deploy() {
src="$1"
dst="$2"
shift 2
cmd="rsync -az --delete --no-perms --no-owner --no-group"
for excl in "$@"; do
cmd="$cmd --exclude=$excl"
done
cmd="$cmd -e 'ssh -p ${SSH_PORT:-22} -i ~/.ssh/id_ed25519' $src $USERNAME@$HOST:$dst"
echo "$cmd"
eval $cmd
}
# Déployer les dossiers buildés
- rsync_deploy site/ "$PROD_PATH/site/" "accounts/" "cache/" "sessions/"
- rsync_deploy vendor/ "$PROD_PATH/vendor/"
- rsync_deploy kirby/ "$PROD_PATH/kirby/"
- rsync_deploy assets/ "$PROD_PATH/assets/"
- rsync_deploy content/ "$PROD_PATH/content/"
- rsync_deploy media/ "$PROD_PATH/media/"
- rsync_deploy .htaccess "$PROD_PATH/"
- rsync_deploy index.php "$PROD_PATH/"
- echo "✅ Déploiement terminé !"
Variables CI/CD à configurer
GitLab → Settings → CI/CD → Variables :
| Variable | Valeur | Protégé | Masqué |
|---|---|---|---|
SSH_PRIVATE_KEY |
Contenu de ~/.ssh/id_ed25519 |
✅ | ✅ |
HOST |
203.0.113.10 (IP du VPS) |
✅ | ❌ |
USERNAME |
debian |
✅ | ❌ |
SSH_PORT |
22 (ou autre si modifié) |
❌ | ❌ |
PROD_PATH |
/var/www/monsite.com |
✅ | ❌ |
Obtenir la clé SSH privée :
cat ~/.ssh/id_ed25519
# Copiez TOUT le contenu (-----BEGIN ... -----END)
Forgejo Actions (SSH/rsync)
Avantages
- ✅ Libre : Alternative open-source à GitHub
- ✅ Auto-hébergé : Vos données restent chez vous
- ✅ Compatible : Syntaxe proche de GitHub Actions
- ✅ Rapide : rsync incrémental
Configuration
.forgejo/workflows/deploy.yml :
name: Deploy to VPS
on:
push:
branches:
- main
jobs:
deploy:
name: Build and Deploy
runs-on: docker
container:
image: php:8.2-cli # Image PHP avec Composer
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Composer
run: |
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Deploy to VPS
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
HOST: ${{ secrets.HOST }}
USERNAME: ${{ secrets.USERNAME }}
PROD_PATH: ${{ secrets.PROD_PATH }}
run: |
# Installer rsync et SSH
apt-get update -qq
apt-get install -y -qq rsync openssh-client
# Configurer SSH
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
cat > ~/.ssh/config <<EOF
Host *
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
BatchMode yes
IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/config
# Déployer avec rsync
echo "🚀 Déploiement..."
rsync -avz --delete \
--exclude 'site/accounts/' \
--exclude 'site/cache/' \
--exclude 'site/sessions/' \
--exclude '.git' \
--exclude '.github' \
--exclude '.forgejo' \
--exclude 'node_modules' \
-e "ssh -i ~/.ssh/id_ed25519" \
./ $USERNAME@$HOST:$PROD_PATH/
echo "✅ Déploiement terminé !"
Secrets à configurer
Dans Forgejo : Settings → Secrets → Actions
| Secret | Valeur |
|---|---|
SSH_PRIVATE_KEY |
Clé privée SSH complète |
HOST |
IP ou domaine du VPS |
USERNAME |
Utilisateur SSH |
PROD_PATH |
Chemin absolu sur le VPS |
💡 Note : Si vous utilisez GitLab, la configuration des secrets est identique (Settings → CI/CD → Variables)
Forgejo Actions (FTP)
Quand utiliser FTP ?
- ✅ Hébergement mutualisé (pas d'accès SSH)
- ✅ Hébergeur impose FTP uniquement
- ❌ Plus lent que SSH/rsync
- ❌ Moins sécurisé (sauf FTPS/SFTP)
Configuration
.forgejo/workflows/deploy-ftp.yml :
name: Deploy via FTP
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy to FTP
runs-on: docker
container:
image: forgejo-ci-php:latest # Image custom (voir ci-dessous)
steps:
- name: Checkout code
run: |
git clone --depth 1 --branch main \
https://forge.example.com/${{ github.repository }}.git .
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Deploy via FTP
env:
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
FTP_HOST: ${{ secrets.FTP_HOST }}
run: |
# Installer lftp (client FTP puissant)
apt-get update -qq && apt-get install -y -qq lftp
# Script lftp
cat > /tmp/lftp-script.txt <<SCRIPT
set ftp:ssl-allow no
open -u $FTP_USERNAME,$FTP_PASSWORD $FTP_HOST
# Synchroniser les dossiers (mirror --reverse = upload)
mirror --reverse --verbose --ignore-time --parallel=10 \
-x accounts/ -x cache/ -x sessions/ \
site site
mirror --reverse --verbose --ignore-time --parallel=10 \
kirby kirby
mirror --reverse --verbose --ignore-time --parallel=10 \
vendor vendor
mirror --reverse --verbose --ignore-time --parallel=10 \
assets assets
mirror --reverse --verbose --ignore-time --parallel=10 \
content content
# Upload des fichiers individuels
put .htaccess
put index.php
quit
SCRIPT
# Exécuter
lftp -f /tmp/lftp-script.txt
echo "✅ Déploiement FTP terminé !"
Secrets FTP
| Secret | Valeur |
|---|---|
FTP_HOST |
ftp.example.com |
FTP_USERNAME |
Utilisateur FTP |
FTP_PASSWORD |
Mot de passe FTP |
Image Docker optimisée pour Kirby
Pourquoi créer une image custom ?
Sans image custom :
Chaque CI installe : Composer + dépendances + rsync/lftp
→ Temps : 2-5 minutes
→ Bande passante gaspillée
Avec image custom :
Image pré-configurée avec tout installé
→ Temps : 30 secondes - 1 minute
→ CI plus rapide et stable
Créer l'image Docker
Dockerfile :
FROM php:8.2-cli
# Métadonnées
LABEL maintainer="votre-email@example.com"
LABEL description="Image PHP optimisée pour CI Kirby CMS"
# Installation des extensions PHP nécessaires pour Kirby
RUN apt-get update && apt-get install -y \
# Extensions PHP
libzip-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
# Outils de déploiement
rsync \
openssh-client \
lftp \
git \
unzip \
# Nettoyage
&& rm -rf /var/lib/apt/lists/*
# Configurer GD (images)
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd zip
# Installer Composer
RUN curl -sS https://getcomposer.org/installer | php -- \
--install-dir=/usr/local/bin --filename=composer
# Définir Composer en mode superuser (pour CI)
ENV COMPOSER_ALLOW_SUPERUSER=1
# Optimisations Composer
RUN composer global config --no-plugins allow-plugins.composer/installers true
# Version et vérification
RUN php -v && composer --version && rsync --version
WORKDIR /workspace
CMD ["/bin/bash"]
Builder et publier l'image
Option 1 : Forgejo Container Registry (recommandé - auto-hébergé)
# Builder l'image
docker build -t forge.example.com/votre-user/kirby-ci:latest .
# Tester localement
docker run --rm -it forge.example.com/votre-user/kirby-ci:latest bash
composer --version
rsync --version
# Login sur votre registry Forgejo
docker login forge.example.com
# Publier
docker push forge.example.com/votre-user/kirby-ci:latest
Option 2 : GitLab Container Registry
# Builder
docker build -t registry.gitlab.com/votre-user/kirby-ci:latest .
# Login GitLab
docker login registry.gitlab.com
# Publier
docker push registry.gitlab.com/votre-user/kirby-ci:latest
Option 3 : Docker Hub (public)
# Builder
docker build -t votre-user/kirby-ci:latest .
# Login Docker Hub
docker login
# Publier
docker push votre-user/kirby-ci:latest
Utiliser l'image dans la CI
GitLab CI :
build_prod:
stage: build
image: registry.gitlab.com/votre-user/kirby-ci:latest # Votre image custom
script:
- composer install --no-dev --optimize-autoloader
Forgejo Actions :
jobs:
deploy:
runs-on: docker
container:
image: forge.example.com/votre-user/kirby-ci:latest
steps:
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
Gain de temps :
- Avant : ~3-5 min (install PHP + Composer + tools)
- Après : ~30s - 1 min (juste
composer install)
Configuration des secrets
Clé SSH pour la CI
1. Générer une clé dédiée à la CI (recommandé) :
# Sur votre machine locale
ssh-keygen -t ed25519 -C "ci-deploy-kirby" -f ~/.ssh/ci_deploy
# Deux fichiers créés :
# ~/.ssh/ci_deploy (PRIVÉE - pour la CI)
# ~/.ssh/ci_deploy.pub (PUBLIQUE - pour le VPS)
2. Ajouter la clé publique au VPS :
# Copier la clé publique
cat ~/.ssh/ci_deploy.pub
# Sur le VPS
ssh debian@VPS
vim ~/.ssh/authorized_keys
# Collez la clé publique sur une nouvelle ligne
3. Ajouter la clé privée dans les secrets CI :
# Afficher la clé PRIVÉE
cat ~/.ssh/ci_deploy
# Copiez TOUT (-----BEGIN ... -----END)
# Puis ajoutez dans les secrets CI sous le nom SSH_PRIVATE_KEY
Vérification
Tester la clé depuis votre machine :
ssh -i ~/.ssh/ci_deploy debian@VPS
# Doit fonctionner sans mot de passe
Déploiement multi-environnements
Staging + Production
.gitlab-ci.yml :
stages:
- build
- deploy-staging
- deploy-production
build:
stage: build
image: votre-user/kirby-ci:latest
script:
- composer install --no-dev --optimize-autoloader
artifacts:
paths:
- vendor/
- kirby/
- site/
- assets/
- .htaccess
- index.php
# Déploiement automatique sur staging (toutes les branches)
deploy_staging:
stage: deploy-staging
image: alpine:latest
only:
- branches
except:
- main
before_script:
- apk add --no-cache rsync openssh
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
- chmod 600 ~/.ssh/id_ed25519
script:
- rsync -avz --delete \
--exclude 'site/accounts/' \
--exclude 'site/cache/' \
--exclude 'site/sessions/' \
-e "ssh -i ~/.ssh/id_ed25519" \
./ $STAGING_USERNAME@$STAGING_HOST:$STAGING_PATH/
# Déploiement manuel sur production (branche main uniquement)
deploy_production:
stage: deploy-production
image: alpine:latest
only:
- main
when: manual # Nécessite une action manuelle
before_script:
- apk add --no-cache rsync openssh
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
- chmod 600 ~/.ssh/id_ed25519
script:
- rsync -avz --delete \
--exclude 'site/accounts/' \
--exclude 'site/cache/' \
--exclude 'site/sessions/' \
-e "ssh -i ~/.ssh/id_ed25519" \
./ $PROD_USERNAME@$PROD_HOST:$PROD_PATH/
Variables supplémentaires :
| Variable | Staging | Production |
|---|---|---|
STAGING_HOST |
staging.example.com |
- |
STAGING_USERNAME |
debian |
- |
STAGING_PATH |
/var/www/staging.example.com |
- |
PROD_HOST |
- | example.com |
PROD_USERNAME |
- | debian |
PROD_PATH |
- | /var/www/example.com |
Optimisations
Cache Composer
GitLab CI :
build_prod:
stage: build
image: composer:2
cache:
key: composer-cache
paths:
- vendor/
script:
- composer install --no-dev --optimize-autoloader
Forgejo Actions :
- name: Cache Composer
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
💡 Note : Forgejo Actions supporte la syntaxe GitHub Actions (compatibilité)
Déploiement incrémental (rsync optimisé)
# Ne synchroniser que les fichiers modifiés
rsync -avz --delete --checksum \
--exclude 'site/accounts/' \
--exclude 'site/cache/' \
--exclude 'site/sessions/' \
--exclude 'media/' \
-e "ssh -i ~/.ssh/id_ed25519" \
./ $USERNAME@$HOST:$PROD_PATH/
Options rsync importantes :
| Option | Description |
|---|---|
-a |
Mode archive (préserve tout) |
-v |
Verbeux (affiche les fichiers) |
-z |
Compression pendant le transfert |
--delete |
Supprime les fichiers distants en trop |
--checksum |
Compare par checksum (plus précis) |
--dry-run |
Simulation (ne fait rien) |
Rollback rapide
Script de rollback :
rollback:
stage: deploy
when: manual
script:
- ssh $USERNAME@$HOST "cd $PROD_PATH && git reset --hard HEAD~1"
Notifications
Slack
GitLab CI :
after_script:
- |
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"✅ Déploiement de $CI_PROJECT_NAME réussi !\"}" \
$SLACK_WEBHOOK_URL
Variables :
SLACK_WEBHOOK_URL: URL du webhook Slack
Discord
after_script:
- |
curl -X POST -H 'Content-Type: application/json' \
-d "{\"content\":\"✅ **$CI_PROJECT_NAME** déployé sur production !\"}" \
$DISCORD_WEBHOOK_URL
Troubleshooting
Erreur "Permission denied (publickey)"
Cause : La clé SSH n'est pas reconnue par le VPS.
Solutions :
- Vérifier que la clé publique est bien dans
~/.ssh/authorized_keyssur le VPS - Vérifier les permissions :
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys - Vérifier le format de la clé privée dans les secrets (doit inclure
-----BEGINet-----END)
Erreur "Host key verification failed"
Cause : Le serveur SSH demande une confirmation.
Solution : Désactiver la vérification dans la config SSH :
before_script:
- |
cat > ~/.ssh/config <<EOF
Host *
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
EOF
Composer install échoue
Erreur : ext-gd is missing
Solution 1 : Ignorer les requirements de plateforme :
composer install --no-dev --optimize-autoloader --ignore-platform-req=ext-gd
Solution 2 : Utiliser une image avec GD pré-installé (image custom)
rsync trop lent
Optimisations :
# Paralléliser avec --partial-dir
rsync -avz --delete --partial-dir=.rsync-partial \
--exclude 'media/' \
./ $USERNAME@$HOST:$PROD_PATH/
# Ou exclure les gros dossiers (uploads manuels)
rsync -avz --delete \
--exclude 'media/' \
--exclude 'assets/tiles/' \
./ $USERNAME@$HOST:$PROD_PATH/
FTP trop lent
Optimisation lftp :
mirror --reverse --verbose --parallel=20 \
--exclude-glob cache/ \
--exclude-glob sessions/ \
site site
Augmenter --parallel (jusqu'à 20-30 connexions simultanées)
Comparaison des méthodes
| Critère | SSH/rsync | FTP/lftp |
|---|---|---|
| Vitesse | ⭐⭐⭐⭐⭐ Très rapide | ⭐⭐⭐ Moyen |
| Sécurité | ⭐⭐⭐⭐⭐ SSH chiffré | ⭐⭐ FTP non chiffré (FTPS mieux) |
| Fiabilité | ⭐⭐⭐⭐⭐ Très stable | ⭐⭐⭐ Dépend du serveur FTP |
| Compatibilité | ⭐⭐⭐ VPS/dédié | ⭐⭐⭐⭐⭐ Tous hébergements |
| Facilité | ⭐⭐⭐⭐ Simple avec clés SSH | ⭐⭐⭐⭐⭐ Très simple |
| Bande passante | ⭐⭐⭐⭐⭐ Optimisée (delta) | ⭐⭐⭐ Retransfère tout |
Recommandation :
- VPS/Serveur dédié → SSH/rsync (meilleure option)
- Hébergement mutualisé → FTP/lftp (seule option souvent)
Exemple complet GitLab CI (production-ready)
.gitlab-ci.yml :
stages:
- build
- test
- deploy
variables:
COMPOSER_ALLOW_SUPERUSER: "1"
# ===== BUILD =====
build:
stage: build
image: votre-user/kirby-ci:latest
cache:
key: composer-$CI_COMMIT_REF_SLUG
paths:
- vendor/
script:
- composer install --no-dev --optimize-autoloader
artifacts:
paths:
- vendor/
- kirby/
- site/
- assets/
- content/
- index.php
- .htaccess
expire_in: 1 hour
# ===== TEST =====
test:
stage: test
image: votre-user/kirby-ci:latest
dependencies:
- build
script:
- echo "🧪 Vérification de la structure Kirby..."
- test -d kirby || exit 1
- test -f index.php || exit 1
- test -f .htaccess || exit 1
- echo "✅ Structure OK"
# ===== DEPLOY PRODUCTION =====
deploy_production:
stage: deploy
image: alpine:latest
only:
- main
when: manual # Déploiement manuel sur prod
dependencies:
- build
before_script:
- apk add --no-cache rsync openssh
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
- chmod 600 ~/.ssh/id_ed25519
- |
cat > ~/.ssh/config <<EOF
Host *
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
BatchMode yes
IdentitiesOnly yes
EOF
- chmod 600 ~/.ssh/config
script:
- echo "🚀 Déploiement sur $PROD_HOST..."
- |
rsync -avz --delete --checksum \
--exclude 'site/accounts/' \
--exclude 'site/cache/' \
--exclude 'site/sessions/' \
--exclude '.git' \
--exclude '.gitlab-ci.yml' \
-e "ssh -p ${SSH_PORT:-22} -i ~/.ssh/id_ed25519" \
./ $USERNAME@$PROD_HOST:$PROD_PATH/
- echo "✅ Déploiement terminé !"
after_script:
- |
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"✅ $CI_PROJECT_NAME déployé en production\"}" \
$SLACK_WEBHOOK_URL || true
Checklist déploiement CI/CD
Avant de mettre en place la CI/CD :
- VPS configuré et accessible en SSH
- Clé SSH dédiée générée pour la CI
- Clé publique ajoutée sur le VPS (
~/.ssh/authorized_keys) - Connexion SSH testée depuis votre machine
- Secrets CI configurés (SSH_PRIVATE_KEY, HOST, USERNAME, PROD_PATH)
- Fichier
.gitlab-ci.ymlou.forgejo/workflows/deploy.ymlcréé - Test de déploiement sur branche de test
- Vérification du site après déploiement
- Notifications configurées (optionnel)
- Documentation de rollback prête
Pour aller plus loin
Docker Compose pour tests locaux
docker-compose.yml :
version: '3.8'
services:
kirby:
build: .
volumes:
- ./:/workspace
working_dir: /workspace
command: php -S 0.0.0.0:8000
ports:
- "8000:8000"
# Tester localement
docker-compose up
# Ouvrir http://localhost:8000
Tests automatisés
test:
stage: test
image: votre-user/kirby-ci:latest
script:
- composer require --dev phpunit/phpunit
- vendor/bin/phpunit tests/
Monitoring post-déploiement
after_script:
# Vérifier que le site répond
- |
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://example.com)
if [ "$STATUS" != "200" ]; then
echo "❌ Le site ne répond pas (HTTP $STATUS)"
exit 1
fi
echo "✅ Site accessible (HTTP 200)"
Ressources
Docker :
- Docker Hub - Registry d'images
- Dockerfile reference
CI/CD (solutions libres) :
- Forgejo Actions - Alternative libre auto-hébergée
- GitLab CI - Solution mature et complète
- Woodpecker CI - CI/CD minimaliste et libre
Déploiement :
Temps de mise en place : 1-2h pour la première configuration, puis déploiements en 2-5 minutes ! 🚀