TL;DR — Résumé Rapide
GitHub Actions: créez des pipelines de déploiement automatisés avec protection des environnements, gestion des secrets, cibles multiples et rollback.
Déployer manuellement — se connecter en SSH à un serveur, lancer des commandes de build, croiser les doigts — est source d’erreurs, intraçable et ne passe pas à l’échelle. GitHub Actions permet de définir tout le pipeline de déploiement sous forme de code : lint, tests, build, approbation, déploiement et notification — le tout déclenché automatiquement à chaque push sur main. Ce guide couvre la création d’un workflow de déploiement automatisé en production, du premier fichier YAML aux déploiements multi-cibles, à la protection des environnements et aux stratégies de rollback.
Prérequis
Avant de créer votre workflow de déploiement, assurez-vous d’avoir en place :
- Un dépôt GitHub avec du code applicatif (exemples Node.js tout au long du guide)
- Un environnement cible — compte Cloudflare Workers, un VPS avec accès SSH, ou un runner auto-hébergé Windows pour IIS
- Une connaissance de base du YAML — les workflows GitHub Actions sont des fichiers YAML où l’indentation est importante
- L’accès aux paramètres du dépôt GitHub pour stocker des secrets et créer des environnements
Concepts de Base de GitHub Actions
Un workflow GitHub Actions est un fichier YAML stocké dans .github/workflows/. Il est déclenché par un ou plusieurs événements (push, pull request, planification, déclenchement manuel). Un workflow contient un ou plusieurs jobs. Chaque job s’exécute sur un runner — une machine virtuelle hébergée par GitHub (Ubuntu, Windows, macOS) ou auto-hébergée. Chaque job contient des steps séquentiels, chacun exécutant soit une commande shell (run), soit une unité réutilisable appelée action (uses).
Les blocs fondamentaux :
name: Deploy # nom du workflow dans l'onglet Actions
on: # déclencheur
push:
branches: [main]
jobs:
deploy: # ID du job
runs-on: ubuntu-latest # runner
steps:
- uses: actions/checkout@v4 # action (récupère le code source)
- run: npm ci # commande shell
- run: npm run build
Les jobs s’exécutent en parallèle par défaut. Utilisez needs: [job-id] pour imposer un ordre.
Votre Premier Workflow de Déploiement
Voici un workflow complet pour un projet Node.js qui déploie sur Cloudflare Workers avec Wrangler. Il exécute d’abord lint et tests, puis build, puis déploie — uniquement sur les pushs vers main.
name: Déployer sur Cloudflare Workers
on:
push:
branches: [main]
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm run lint
- run: npm test
build:
needs: lint-and-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Déployer avec Wrangler
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
- name: Notifier le succès sur Slack
if: success()
run: |
curl -s -X POST "${{ secrets.SLACK_WEBHOOK }}" \
-H "Content-Type: application/json" \
-d "{\"text\":\"Déployé ${{ github.sha }} en production par ${{ github.actor }}\"}"
Le bloc concurrency en haut empêche deux déploiements de se chevaucher. Si vous faites deux pushs rapidement, la première exécution est annulée avant que la seconde commence.
Règles de Protection des Environnements
Pousser directement en production sans vérification humaine est risqué pour les systèmes critiques. Les environnements GitHub permettent d’ajouter des règles de protection à tout job qui les cible.
Pour configurer la protection d’environnement :
- Allez dans Settings → Environments de votre dépôt
- Cliquez sur New environment et nommez-le
production - Activez Required reviewers — ajoutez un ou plusieurs utilisateurs ou équipes GitHub
- Définissez optionnellement un Wait timer (par exemple, 10 minutes) avant que le job puisse s’exécuter
- Restreignez optionnellement les branches pouvant déployer dans cet environnement (par exemple, uniquement
main)
Une fois configuré, tout job avec environment: production se mettra en pause et attendra l’approbation d’un relecteur avant de continuer. Le relecteur voit le déploiement en attente dans l’interface GitHub et peut approuver ou rejeter avec un commentaire.
Gestion des Secrets
Ne codez jamais en dur des tokens API, clés SSH ou mots de passe dans les fichiers de workflow. GitHub propose trois niveaux de stockage des secrets :
Secrets de dépôt — Disponibles pour tous les workflows du repo. Allez dans Settings → Secrets and variables → Actions → New repository secret.
Secrets d’environnement — Limités à un environnement spécifique (par exemple, production). Exposés uniquement lorsqu’un job cible cet environnement.
Secrets d’organisation — Partagés entre plusieurs dépôts d’une organisation GitHub, idéaux pour les tokens utilisés par de nombreux projets.
Référencez les secrets dans les workflows avec la syntaxe ${{ secrets.NOM_SECRET }} :
- name: Déployer avec Wrangler
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
OIDC (OpenID Connect) est une alternative aux secrets de longue durée pour les fournisseurs cloud qui le supportent (AWS, GCP, Azure). Au lieu de stocker un token statique, le runner demande une credential de courte durée au fournisseur à l’exécution.
Déploiement vers Différentes Cibles
Cloudflare Workers avec Wrangler
L’action cloudflare/wrangler-action gère l’authentification et exécute n’importe quelle commande Wrangler :
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: deploy --env production
VPS via SSH et rsync
Pour un VPS Linux, utilisez SSH pour vous connecter et rsync pour transférer les fichiers :
- name: Déployer sur VPS
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
rsync -az --delete dist/ /var/www/myapp/dist/
systemctl restart myapp
Stockez la clé SSH privée dans les secrets GitHub. Ajoutez la clé publique correspondante dans ~/.ssh/authorized_keys sur le serveur. Utilisez un utilisateur de déploiement dédié avec des permissions minimales — jamais root.
IIS via Runner Auto-Hébergé
Pour les déploiements Windows IIS, exécutez un runner auto-hébergé directement sur le serveur :
deploy-iis:
needs: build
runs-on: [self-hosted, iis-deploy]
environment: production
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: C:\inetpub\wwwroot\myapp
- name: Redémarrer le site IIS
run: |
Import-Module WebAdministration
Restart-WebItem 'IIS:\Sites\MyApp'
shell: powershell
Cache et Performance
Cache des Dépendances
Re-télécharger les packages npm à chaque exécution est une perte de temps. Mettez-les en cache :
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
Pour .NET :
- uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: ${{ runner.os }}-nuget-
Groupes de Concurrence
Les groupes de concurrence évitent les déploiements parallèles — source fréquente de race conditions :
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Comparatif : GitHub Actions vs GitLab CI vs Jenkins
| Fonctionnalité | GitHub Actions | GitLab CI | Jenkins |
|---|---|---|---|
| Hébergement | GitHub (SaaS) | GitLab ou auto-hébergé | Auto-hébergé uniquement |
| Fichier de config | .github/workflows/*.yml | .gitlab-ci.yml | Jenkinsfile (Groovy) |
| Plan gratuit | 2 000 min/mois (privé) | 400 min/mois (privé) | Illimité (votre infra) |
| Marketplace | 20 000+ actions | Limité | 1 800+ plugins |
| Gates d’environnement | Natifs (gratuit pour le public) | Natifs (Ultimate pour les règles) | Via plugins |
| OIDC | AWS, GCP, Azure, Cloudflare | AWS, GCP, Azure | Via plugins |
| Courbe d’apprentissage | Faible | Faible | Élevée (DSL Groovy) |
| Idéal pour | Projets sur GitHub | Monorepos sur GitLab | Pipelines legacy complexes |
Scénario Réel : Pipeline Complet
Un pipeline de production pour Node.js avec notifications Slack :
name: Déploiement Production
on:
push:
branches: [main]
concurrency:
group: production-deploy
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm run lint
test:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm test -- --coverage
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist-${{ github.sha }}
path: dist/
retention-days: 14
deploy:
needs: build
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: dist-${{ github.sha }}
path: dist/
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
- name: Notifier le succès
if: success()
run: |
curl -s -X POST "${{ secrets.SLACK_WEBHOOK }}" \
-d "{\"text\":\"Déployé ${{ github.sha }} par ${{ github.actor }}\"}"
- name: Notifier l'échec
if: failure()
run: |
curl -s -X POST "${{ secrets.SLACK_WEBHOOK }}" \
-d "{\"text\":\"ÉCHEC du déploiement pour ${{ github.sha }}\"}"
Badges de Statut
Ajoutez un badge de statut en direct à votre README :

Pièges et Cas Limites
Le masquage des secrets ne fonctionne que pour les correspondances exactes. GitHub masque la valeur littérale du secret dans les logs, mais si le secret est encodé en base64 ou URL avant utilisation, la valeur originale peut apparaître sans masque.
Les changements d’image de runner cassent les versions d’outils épinglées. GitHub met à jour ubuntu-latest périodiquement. Si votre workflow dépend d’une version spécifique d’un outil préinstallé, installez-la explicitement avec une action de setup.
cancel-in-progress: true annule l’exécution en cours, pas celle qui arrive. Le nouveau push l’emporte. C’est presque toujours ce que vous voulez pour les déploiements.
Les secrets d’environnement ne sont pas disponibles pour les pull requests de forks. C’est intentionnel — les forks ne peuvent pas accéder aux secrets pour prévenir les fuites.
Résolution des Problèmes
Le workflow ne se déclenche pas sur un push vers main. Vérifiez le filtre on.push.branches — le nom de la branche doit correspondre exactement. Confirmez que le fichier de workflow est bien dans .github/workflows/.
Le secret est disponible mais l’authentification Wrangler échoue. Confirmez que le nom du secret correspond exactement (sensible à la casse). Vérifiez que le token API Cloudflare a les permissions correctes : Workers Scripts: Edit et Account: Read.
Le job attend indéfiniment l’approbation de l’environnement. Vérifiez que vous êtes listé comme relecteur requis de l’environnement. Confirmez que le nom de l’environnement dans le YAML correspond exactement au nom dans Settings.
Résumé
- Définissez les workflows sous forme de fichiers YAML dans
.github/workflows/— ils sont versionnés avec votre code - Structurez les pipelines en jobs séquentiels : lint → test → build → deploy, en utilisant
needspour imposer l’ordre - Utilisez
environment: productionavec des relecteurs requis pour des gates d’approbation humaine - Stockez tous les secrets dans le gestionnaire de secrets GitHub — jamais dans le fichier YAML
- Les déploiements Cloudflare Workers utilisent
cloudflare/wrangler-action; les cibles VPS utilisent SSH/rsync ; IIS utilise un runner auto-hébergé - Ajoutez des groupes de
concurrencyaveccancel-in-progress: truepour éviter les déploiements qui se chevauchent - Mettez en cache les dépendances avec
actions/setup-node cache: npmpour des exécutions plus rapides - Nommez les artefacts avec
${{ github.sha }}pour faciliter le rollback en relançant le workflow sur n’importe quel commit précédent