📍 Article principal du cluster : Automatisation pour PME ouest-africaines : le guide complet 2026
Ce tutoriel fait partie du cluster « Automatisation ». Pour la vue d’ensemble (no-code, n8n, scripts, IA agents), commencer par le pilier.
Introduction
Un développeur freelance basé à Dakar maintient quatre sites WordPress et deux applications Node.js pour ses clients ouest-africains. Chaque mise à jour suit le même rituel : SSH sur le serveur, git pull, gestion des permissions, redémarrage du service, vérification que rien n’est cassé. Multipliez par six sites et dix déploiements par mois : c’est une journée pleine perdue dans des tâches mécaniques. GitHub Actions remplace ce rituel par un pipeline qui se déclenche tout seul à chaque push, qui teste, qui déploie, et qui alerte en cas d’erreur.
Ce tutoriel pas-à-pas couvre la mise en place complète d’un pipeline CI/CD avec GitHub Actions pour un projet web typique : tests automatiques sur chaque pull request, déploiement automatique sur push main, gestion propre des secrets, notification Telegram en cas d’échec. Vous repartirez avec un workflow YAML opérationnel, adaptable à WordPress, Node.js, Python, Hugo, ou tout autre projet de ce type.
Prérequis
- Un compte GitHub (gratuit) avec un dépôt — public idéalement (minutes Actions illimitées) ou privé (quota selon plan)
- Un serveur de destination accessible en SSH (VPS Hetzner, OVH, ou équivalent)
- Une clé SSH dédiée au déploiement (on la créera ensemble)
- Notions de base Git (clone, commit, push, branches)
- YAML lisible (pas besoin de maîtrise — la syntaxe se découvre vite)
- Temps estimé : 2 h pour le tutoriel, 3 à 4 h pour adapter à votre projet réel
Étape 1 — Comprendre les briques GitHub Actions
GitHub Actions repose sur quatre concepts qui s’emboîtent. Un workflow est un fichier YAML placé dans .github/workflows/ de votre dépôt — vous pouvez en avoir plusieurs par projet (un pour les tests, un pour le déploiement, un pour les releases). Chaque workflow contient un ou plusieurs jobs, qui s’exécutent en parallèle par défaut. Chaque job tourne sur un runner, généralement une VM Ubuntu fournie par GitHub. Et chaque job enchaîne des steps : soit des commandes shell brutes, soit des actions réutilisables (actions/checkout, actions/setup-node, etc.) publiées par GitHub ou la communauté.
Côté tarification 2026 : pour les dépôts publics, l’usage est entièrement gratuit, sans limite de minutes. Pour les dépôts privés, chaque compte reçoit un quota mensuel de minutes selon le plan (Free, Pro, Team, Enterprise) ; depuis le 1er janvier 2026, GitHub a baissé d’environ 40 % le tarif des runners hébergés et introduit un petit frais de plateforme par minute. Pour une PME qui héberge ses sources sur dépôts publics ou qui démarre, on reste très largement sous les seuils gratuits.
Étape 2 — Premier workflow : tests sur chaque pull request
Avant de déployer, on vérifie que le code n’est pas cassé. Créez le fichier .github/workflows/tests.yml à la racine de votre dépôt avec ce contenu (exemple Node.js) :
name: Tests
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout du code
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: '20'
cache: 'npm'
- name: Installation des dépendances
run: npm ci
- name: Lint
run: npm run lint --if-present
- name: Tests unitaires
run: npm test
Plusieurs choses se passent ici. Le déclencheur on: définit deux scénarios : à chaque pull request vers main et à chaque push direct sur main. Le job test tourne sur la dernière Ubuntu LTS hébergée par GitHub. Les actions actions/checkout@v5 et actions/setup-node@v5 sont les briques officielles maintenues par GitHub — toujours utiliser les tags majeurs (@v5 ou @v6 selon disponibilité) pour bénéficier des correctifs sans surprise. npm ci est préféré à npm install en CI : il installe à partir du package-lock.json de manière déterministe et plus rapide. Le --if-present évite de faire échouer le pipeline si le script lint n’existe pas dans package.json.
Committez et poussez ce fichier. Sous l’onglet Actions de votre dépôt GitHub, vous verrez le workflow s’exécuter en quelques secondes. À chaque pull request future, GitHub bloquera le merge si les tests échouent — la qualité de code devient automatique au lieu de dépendre de la discipline humaine.
Étape 3 — Préparer la clé SSH de déploiement
Pour que GitHub Actions puisse pousser du code sur votre serveur, il faut une clé SSH dédiée — jamais celle de votre admin personnel. Sur votre poste de travail, générez une nouvelle paire :
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/gh_deploy -N ""
Cette commande crée deux fichiers : ~/.ssh/gh_deploy (la clé privée, à donner à GitHub) et ~/.ssh/gh_deploy.pub (la clé publique, à installer sur le serveur). L’algorithme ed25519 est le standard moderne — plus court que RSA, plus sûr, supporté partout. Le -N "" crée la clé sans passphrase, indispensable pour une clé qui sera utilisée par un automate.
Sur le serveur de destination, créez un utilisateur dédié deploy (jamais déployer en root direct) et installez la clé publique :
# Sur le serveur, en root :
useradd -m -s /bin/bash deploy
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
# Copier la clé publique gh_deploy.pub dans /home/deploy/.ssh/authorized_keys
nano /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
# Donner à l'utilisateur deploy les droits sur le dossier du site
usermod -aG www-data deploy
chown -R deploy:www-data /var/www/votre-site
chmod -R g+w /var/www/votre-site
Testez la connexion depuis votre poste : ssh -i ~/.ssh/gh_deploy deploy@votre-serveur.com. Si vous entrez sans mot de passe, c’est gagné. Cette clé doit avoir strictement les droits de déploiement, rien de plus — pas d’accès sudo, pas de droits système. C’est le principe du moindre privilège évoqué dans le pilier automatisation.
Étape 4 — Configurer les secrets GitHub
La clé privée ne doit jamais figurer dans le dépôt. GitHub fournit un coffre-fort pour les secrets, accessible uniquement aux workflows de votre dépôt. Dans l’interface GitHub : Settings → Secrets and variables → Actions → New repository secret. Créez trois secrets :
- SSH_PRIVATE_KEY : le contenu intégral de
~/.ssh/gh_deploy(commandecat ~/.ssh/gh_deploysur votre poste, puis copier-coller — incluez les lignes-----BEGIN ...et-----END ...). - DEPLOY_HOST : le nom de domaine ou l’IP de votre serveur (ex.
vps.votre-pme.snou5.161.42.123). - DEPLOY_USER :
deploy(l’utilisateur créé à l’étape 3).
Ces secrets sont chiffrés au repos chez GitHub et exposés au workflow uniquement comme variables d’environnement ${{ secrets.SSH_PRIVATE_KEY }}. Ils n’apparaissent jamais dans les logs, même si vous écriviez accidentellement echo dessus — GitHub remplace automatiquement la valeur par *** dans la sortie.
Étape 5 — Workflow de déploiement complet
Créez maintenant .github/workflows/deploy.yml, le pipeline qui fera le déploiement réel après chaque push réussi sur main :
name: Déploiement Production
on:
push:
branches: [main]
workflow_dispatch: # permet aussi le déclenchement manuel
concurrency:
group: deploy-production
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
needs: [] # ajouter "test" ici si vous voulez bloquer sur les tests
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H ${{ secrets.DEPLOY_HOST }} >> ~/.ssh/known_hosts
- name: Déploiement via rsync
run: |
rsync -avz --delete \
--exclude='.git' \
--exclude='.github' \
--exclude='node_modules' \
--exclude='.env' \
-e "ssh -i ~/.ssh/deploy_key" \
./ ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:/var/www/votre-site/
- name: Commandes post-déploiement
run: |
ssh -i ~/.ssh/deploy_key ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} \
"cd /var/www/votre-site && npm ci --production && sudo systemctl reload nginx"
- name: Notification Telegram en cas d'échec
if: failure()
run: |
curl -sS -X POST "https://api.telegram.org/bot${{ secrets.TG_BOT_TOKEN }}/sendMessage" \
-d "chat_id=${{ secrets.TG_CHAT_ID }}" \
-d "text=🔴 Déploiement ÉCHOUÉ — ${{ github.repository }} commit ${{ github.sha }}"
Plusieurs subtilités méritent l’arrêt sur image. Le bloc concurrency empêche deux déploiements simultanés du même environnement de se marcher dessus — indispensable si plusieurs développeurs poussent à la suite. workflow_dispatch ajoute un bouton « Run workflow » dans l’interface GitHub pour redéployer manuellement en cas de besoin. ssh-keyscan ajoute la clé du serveur à known_hosts pour éviter le prompt de validation au premier contact. rsync avec --delete synchronise vraiment le contenu (les fichiers supprimés du dépôt sont supprimés du serveur), tandis que les --exclude protègent les fichiers sensibles ou non-versionnés. Enfin, le step Notification Telegram ne s’exécute qu’en cas d’échec grâce à if: failure() — pas de spam quand tout va bien.
Étape 6 — Tester et valider le pipeline
Le pipeline est prêt. Faites un commit trivial sur la branche main (changement d’une virgule dans un README, par exemple) et poussez. Sous l’onglet Actions de votre dépôt, vous verrez le workflow se déclencher : checkout, setup SSH, rsync, commandes post-déploiement. Le pipeline complet pour un site moyen prend 30 à 90 secondes.
Pour valider la robustesse, déclenchez délibérément un échec : modifiez temporairement le secret DEPLOY_HOST avec une valeur invalide, poussez un commit, et vérifiez que le step Notification Telegram envoie bien le message d’alerte. Restaurez ensuite le bon hostname. Sans ce test négatif, vous ne saurez pas si vos alertes fonctionnent le jour où vous en aurez besoin.
Pour les projets WordPress, le post-déploiement peut inclure des commandes WP-CLI (wp cache flush, wp core update-db) en plus du reload nginx. Pour les projets statiques (Hugo, Next.js export), le post-déploiement se limite généralement à un rsync vers le dossier servi par nginx.
Étape 7 — Sécurité et bonnes pratiques
Quatre principes éliminent la quasi-totalité des accidents de pipeline CI/CD. Premier : épingler les actions tierces à un commit SHA plutôt qu’à un tag (uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 au lieu de @v4). C’est verbose mais c’est la seule garantie qu’un attaquant qui détourne le tag d’une action populaire ne puisse pas vous compromettre. Pour les actions officielles GitHub (actions/*), la confiance est élevée et le tag majeur reste acceptable.
Deuxième : toujours utiliser permissions: au niveau workflow ou job pour restreindre le token GitHub injecté. Par défaut, le GITHUB_TOKEN a des permissions larges. Mettez permissions: { contents: read } sauf si vous devez écrire (par exemple pour publier une release).
Troisième : protéger la branche main dans les paramètres du dépôt — exiger une pull request, exiger que les tests passent avant merge, exiger une review. Sans cela, n’importe qui avec accès écriture peut bypasser la CI en poussant directement.
Quatrième : faire tourner les secrets régulièrement, surtout après le départ d’un collaborateur. Un script Bash hebdomadaire qui régénère les clés SSH de déploiement et met à jour les secrets via l’API GitHub se met en place en quelques heures et ferme l’angle d’attaque le plus courant.
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| Le workflow ne se déclenche pas | Fichier mal placé ou syntaxe YAML invalide | Vérifier le chemin .github/workflows/ exact (S à workflows), passer le YAML dans un linter |
| Erreur « Permission denied » SSH | Clé privée mal copiée dans le secret (caractères perdus, BEGIN/END manquants) | Recopier le contenu intégral de la clé, ligne par ligne, en incluant les marqueurs |
| Échec « Host key verification failed » | Oubli du ssh-keyscan |
Ajouter le step ssh-keyscan -H $HOST >> ~/.ssh/known_hosts |
| Quota minutes dépassé sur dépôt privé | Workflow lourd qui tourne sur chaque push | Repo public si possible, sinon mettre des conditions if: et utiliser le cache |
| Secret affiché en clair dans les logs | Variable construite à partir d’un secret puis echo | GitHub masque les secrets directement, mais pas leurs dérivés. Ne jamais echo de valeurs construites à partir de secrets |
| Déploiements concurrents qui se marchent dessus | Push successifs rapides sans concurrency control | Bloc concurrency: { group: deploy-production } |
Adaptation au contexte ouest-africain
Trois adaptations spécifiques pour un développeur ou une équipe basée en Afrique de l’Ouest. Première : les runners GitHub-hosted tournent dans des datacenters Microsoft Azure (US East ou Europe selon la file d’attente), donc le déploiement vers un VPS Hetzner allemand est rapide (50-200 ms de latence ajoutée), tandis que le déploiement vers un serveur local Sénégal/Côte d’Ivoire passera par les câbles sous-marins ACE/SAT-3 — comptez 200-400 ms de latence et un débit moindre. Pour les déploiements lourds (gros assets), placez le serveur en Europe.
Deuxième : pour les projets internes sensibles (administration, finance), envisagez Gitea Actions self-hosted plutôt que GitHub. Gitea propose une syntaxe quasi-identique aux GitHub Actions, tourne sur votre VPS européen, et garde le code source sous votre contrôle. C’est traité dans Gitea Actions : CI/CD compatible GitHub — tutoriel 2026.
Troisième : si votre équipe est géographiquement répartie (Dakar + Abidjan + Bamako), exploitez à fond la fonctionnalité « branch protection + required reviews » de GitHub pour formaliser la collaboration asynchrone. Le pipeline CI/CD devient alors un outil de qualité partagée, pas seulement de productivité individuelle.
Tutoriels frères du cluster automatisation
- Cron et systemd timers Linux : automatiser les tâches récurrentes — tutoriel 2026 — pour les tâches récurrentes hors CI/CD (sauvegardes, monitoring, rotation des logs).
- Bash scripting pour sysadmin : sauvegardes, monitoring, déploiements — tutoriel 2026 — pour les scripts shell appelés par les pipelines GitHub Actions.
- Gitea Actions : CI/CD compatible GitHub — tutoriel 2026 — alternative self-hosted quand on veut garder ses sources chez soi.
- CI GitHub Actions pour monorepo Bun : guide 2026 — variante avancée pour les projets Bun/JavaScript modernes.
FAQ
GitHub Actions est-il vraiment gratuit pour une PME ?
Oui pour les dépôts publics : aucune limite de minutes sur les runners hébergés standards. Pour les dépôts privés, chaque compte reçoit un quota mensuel selon le plan (Free, Pro, Team, Enterprise) — généralement plusieurs milliers de minutes, largement suffisant pour les workflows d’une PME. Au-delà du quota, c’est facturé à la minute selon la nouvelle tarification entrée en vigueur le 1er janvier 2026 (–40 % vs 2025 + petit frais de plateforme).
GitHub Actions ou GitLab CI ou Gitea Actions ?
GitHub Actions si votre code est déjà sur GitHub — c’est le choix par défaut, l’écosystème d’actions est le plus riche. GitLab CI si vous utilisez GitLab pour ses fonctionnalités intégrées (issues, registry, etc.). Gitea Actions si vous voulez self-hoster votre forge Git tout en profitant d’une syntaxe quasi-identique à GitHub. Les trois sont matures en 2026 ; la décision dépend principalement du choix de la forge Git.
Comment éviter de stocker la clé SSH dans GitHub ?
Trois alternatives pour les équipes plus exigeantes. Première : OIDC + cloud (AWS, Azure, GCP) — le runner GitHub Actions s’authentifie au cloud sans clé statique. Deuxième : runner self-hosted directement sur le serveur de destination — le « déploiement » devient un simple cp local. Troisième : un proxy de déploiement comme Argo CD ou Coolify qui surveille un dépôt Git et déploie sans GitHub Actions. Pour démarrer, la clé SSH dans Secrets reste le compromis le plus simple.
Mon workflow tourne mais le déploiement n’est pas appliqué, pourquoi ?
Causes les plus fréquentes : permissions insuffisantes de l’utilisateur deploy sur le dossier cible (faire chown + chmod g+w), cache opcode PHP qui sert encore l’ancien code (faire systemctl reload php-fpm en post-déploiement), ou cache CDN/Cloudflare qui ne s’invalide pas (purger via API CDN dans le pipeline). Vérifiez aussi que le rsync ne masque pas son output — un --dry-run manuel reproduit le problème en local.
Faut-il toujours faire tourner les tests dans GitHub Actions ?
Si vous avez une suite de tests, oui — c’est précisément le bénéfice principal d’une CI : exécution garantie sur un environnement neutre, reproductible, à chaque PR et chaque push. Si vous n’avez pas (encore) de tests, GitHub Actions peut quand même servir au déploiement automatique. Mieux vaut un pipeline simple sans tests qu’aucun pipeline du tout ; et c’est le bon moment pour ajouter les premiers tests.
Sources et références
- Documentation officielle GitHub Actions — docs.github.com/actions.
- Billing & usage GitHub Actions — docs.github.com/actions/concepts/billing-and-usage.
- Mise à jour tarifaire 2026 — github.blog : Update to GitHub Actions pricing (16 décembre 2025).
- Marketplace officielle des actions — github.com/marketplace.
- actions/checkout (officiel) — github.com/actions/checkout.
- actions/setup-node (officiel) — github.com/actions/setup-node.
- Bonnes pratiques sécurité — Security hardening for GitHub Actions.
- OpenSSH ed25519 — openssh.com/manual.html.
- rsync man page — download.samba.org/pub/rsync/rsync.1.
Pour aller plus loin
- 🔝 Retour au pilier : Automatisation pour PME ouest-africaines : le guide complet 2026
- Pratique : transformer un de vos sites WordPress de production en pipeline CI/CD complet en suivant ce tutoriel. Mesurer le temps gagné après 1 mois.
- Étapes suivantes : ajouter des tests E2E avec Playwright, intégrer un scan de sécurité (Snyk, Trivy), automatiser les releases sémantiques avec semantic-release.
Mots-clés secondaires : GitHub Actions tutoriel, CI/CD WordPress, déploiement automatique, pipeline YAML, runner Ubuntu, secrets GitHub, rsync SSH, Gitea Actions, branch protection, workflow_dispatch.