Déployer automatiquement
Stratégies de déploiement
GitHub Actions peut déclencher un déploiement après chaque push sur main.
Selon ta cible, plusieurs stratégies sont disponibles :
GitHub Pages
Idéal pour les sites statiques. Intégré nativement à GitHub, zéro infra à gérer.
SSH vers VPS
Tu pousses ton code ou ton image Docker sur un serveur que tu contrôles via SSH.
Docker Hub + restart
Build et push d'une image Docker, puis pull et redémarrage du conteneur sur le serveur.
Fly.io / Vercel
Plateformes cloud avec CLI intégrée à GitHub Actions. Déploiement en une commande.
Déploiement GitHub Pages
GitHub Pages permet d'héberger un site statique directement depuis ton dépôt.
Le workflow officiel utilise actions/upload-pages-artifact et actions/deploy-pages.
name: Deploy to GitHub Pages
on:
push:
branches:
- main # déclenché seulement sur main
permissions:
contents: read
pages: write # permission nécessaire pour Pages
id-token: write # requis par deploy-pages
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build # génère le dossier _site/
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: "_site" # dossier de sortie du build
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Pour activer GitHub Pages, va dans Settings → Pages de ton dépôt et
sélectionne la source GitHub Actions. Une fois activé, chaque push sur
main déclenchera un build et mettra à jour ton site automatiquement.
Déploiement SSH vers un VPS
Pour déployer sur ton propre serveur, tu as besoin d'une clé SSH stockée en secret.
L'action appleboy/ssh-action permet d'exécuter des commandes à distance en une étape.
name: Deploy to VPS
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Sync files via rsync
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SSH_HOST }} # IP ou domaine du VPS
username: ${{ secrets.SSH_USER }} # ex: deploy
key: ${{ secrets.SSH_PRIVATE_KEY }} # clé privée Ed25519
port: ${{ secrets.SSH_PORT }} # par défaut 22
script: |
# Aller dans le dossier de l'appli
cd /var/www/mon-app
# Récupérer le dernier code
git pull origin main
# Reinstaller les dépendances si besoin
npm ci --production
# Redémarrer l'application via PM2
pm2 restart mon-app
Ne stocke jamais une clé SSH dans ton code. Génère une paire de clés dédiée
(ssh-keygen -t ed25519 -C "github-actions"), ajoute la clé publique
dans ~/.ssh/authorized_keys sur ton serveur, et stocke la clé privée
dans un secret GitHub (SSH_PRIVATE_KEY).
Variante : Docker pull + restart
Si tu déploies via Docker, le workflow peut builder l'image, la pousser sur GHCR, puis ordonner au serveur de la récupérer et redémarrer le conteneur :
- name: Deploy via Docker
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
# Tirer la nouvelle image
docker pull ghcr.io/monorg/mon-app:latest
# Redémarrer le conteneur
docker compose -f /var/www/mon-app/compose.yaml up -d --no-deps app
Workflow complet : tests → build → deploy
Un pipeline de CI/CD professionnel enchaîne les étapes : on teste d'abord,
on ne déploie que si tout est vert, et seulement depuis main.
name: CI/CD — Test & Deploy
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# ─────────────────────────────────────────
# JOB 1 : Tests (toujours exécuté)
# ─────────────────────────────────────────
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm" # cache node_modules entre les runs
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
# ─────────────────────────────────────────
# JOB 2 : Build de l'image Docker
# ─────────────────────────────────────────
build:
runs-on: ubuntu-latest
needs: test # attend que les tests passent
if: github.ref == 'refs/heads/main' # seulement sur main
permissions:
contents: read
packages: write # pour pousser sur GHCR
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} # token auto-fourni
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}
# ─────────────────────────────────────────
# JOB 3 : Déploiement en production
# ─────────────────────────────────────────
deploy:
runs-on: ubuntu-latest
needs: build # attend le build Docker
if: github.ref == 'refs/heads/main'
environment: production # environnement protégé
steps:
- name: Deploy to VPS
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
docker pull ghcr.io/${{ github.repository }}:latest
docker compose -f /var/www/mon-app/compose.yaml up -d --no-deps app
echo "Déploiement terminé ✓"
Le mot-clé needs crée une dépendance entre jobs. Si le job
test échoue, le job build ne démarre pas — et donc deploy
non plus. C'est la clé du déploiement conditionnel : on ne déploie jamais un code cassé.
Déploiement conditionnel
Plusieurs mécanismes permettent de contrôler quand un job s'exécute :
# Seulement sur la branche main
if: github.ref == 'refs/heads/main'
# Seulement si le job précédent a réussi (comportement par défaut avec needs:)
if: ${{ success() }}
# Seulement sur un push (pas sur une PR)
if: github.event_name == 'push'
# Seulement si un fichier précis a changé
if: contains(github.event.commits[0].message, '[deploy]')
# Sur un tag de version (ex: v1.2.3)
if: startsWith(github.ref, 'refs/tags/v')
Environnements et protections
GitHub permet de définir des environnements (staging, production…) avec des règles de protection. Un environnement peut exiger une approbation manuelle avant tout déploiement.
deploy:
runs-on: ubuntu-latest
needs: build
environment: production # réf. à l'environnement GitHub
steps:
# Si "Required reviewers" est activé sur cet environnement,
# le workflow s'arrête ici et attend l'approbation manuelle.
- name: Deploy
run: ./deploy.sh
Configure les environnements dans Settings → Environments de ton dépôt. Tu peux y définir des Required reviewers (approbation manuelle obligatoire), des Wait timer (délai avant déploiement) et des secrets spécifiques à cet environnement, différents des secrets globaux du dépôt.
- GitHub Pages, SSH/rsync, Docker+GHCR et les PaaS (Fly.io, Vercel) sont les principales cibles de déploiement depuis Actions.
- Stocke la clé SSH privée dans un secret GitHub — jamais dans le code.
needs:enchaîne les jobs : si les tests échouent, le déploiement ne démarre pas.if: github.ref == 'refs/heads/main'limite le déploiement à la branche principale.environment: productionactive les protections GitHub (approbation manuelle, secrets dédiés).