GitHub et la tarification des runners : ce qui s'est passé en 2025-2026
Jusqu'en 2025, les dépôts privés bénéficiaient d'un quota mensuel de minutes incluses. Le 16 décembre 2025, GitHub a annoncé une tarification à la minute pour l'utilisation des runners — y compris les runners auto-hébergés sur vos propres machines. La discussion GitHub #182089 (ouverte ce même mois, 72 upvotes) résume l'inquiétude : les équipes auraient payé GitHub pour l'orchestration d'un job tournant sur leur propre infrastructure, à 0,002 $ la minute.
Face à une réaction communautaire massive, GitHub a suspendu cette tarification dans les 48 heures. Au 1er septembre 2026, les runners self-hosted sur dépôts privés restent gratuits — la mesure n'a jamais été appliquée. Mais l'annonce a mis en évidence une dépendance structurelle : GitHub peut modifier ses conditions à tout moment. Migrer la chaîne CI/CD vers une forge auto-hébergée, c'est s'affranchir de cette incertitude. Woodpecker CI est conçu précisément pour cet usage : un moteur de pipeline léger, open source (Apache 2.0), qui s'installe aux côtés de Gitea ou Forgejo et ne connaît pas de compteur de minutes.
GitHub Actions runners vs Woodpecker CI auto-hébergé
| Critère | GitHub Actions (runners cloud) | Woodpecker CI sur VPS |
|---|---|---|
| Coût | 0,008 $ / min (Linux) + 0,002 $ / min orchestration sur dépôts privés | Inclus dans le coût fixe du VPS (à partir de `{{vps.start.price}}`) |
| RAM du moteur CI | Runners GitHub-hosted : ressources mutualisées, non maîtrisées | Serveur + agent Woodpecker : moins de 50 Mo RAM cumulés |
| Souveraineté | Code et secrets transitent par l'infrastructure GitHub/Microsoft | Tout reste sur votre VPS — aucun transit externe |
| Syntaxe workflow | `.github/workflows/*.yml` — standard très répandu | `.woodpecker.yml` — syntaxe propre, plus courte, non compatible GitHub Actions |
| Prérequis forge | Aucun (GitHub héberge le dépôt) | Gitea ou Forgejo auto-hébergé (ou GitHub en forge distante) |
| Licence | Propriétaire | Apache 2.0 |
Prérequis avant l'installation
Pour déployer Woodpecker CI dans de bonnes conditions, vérifiez les points suivants.
VPS : 1 vCPU et 1 Go de RAM suffisent pour le serveur Woodpecker, un agent et une forge Gitea ou Forgejo légère. Comptez 2 Go si vous lancez plusieurs builds en parallèle ou si vos jobs compilent des images Docker.
Logiciels : Docker et Docker Compose doivent être installés. Si vous partez d'un VPS vierge, le guide Démarrer avec Docker sur VPS couvre cette étape.
Forge git : Woodpecker CI s'appuie sur OAuth2 pour l'authentification. Il vous faut une instance Gitea ou Forgejo déjà en place et accessible via HTTPS (par exemple sur git.votre-domaine.com). Les guides Héberger Gitea et Héberger Forgejo détaillent cette installation.
Domaine : prévoyez un sous-domaine dédié à Woodpecker — par exemple ci.votre-domaine.com — pointant vers l'IP de votre VPS, avec le port 443 ouvert. Ce sous-domaine sert de WOODPECKER_HOST et d'URL de redirection OAuth2.
Installer Woodpecker CI avec Docker Compose
Créer une application OAuth2 dans Gitea
Dans Gitea, allez dans Paramètres → Applications → Gérer les applications OAuth2. Donnez un nom à l'application (par exemple woodpecker) et renseignez l'URL de redirection : https://ci.votre-domaine.com/authorize. Notez le Client ID et le Client Secret générés — vous en aurez besoin à l'étape suivante.
Si vous utilisez Forgejo, la procédure est identique : Paramètres → Applications → OAuth2.
Créer le fichier docker-compose.yml
Créez le répertoire /opt/woodpecker et placez-y un fichier docker-compose.yml avec les deux services — serveur et agent :
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:v3
restart: always
ports:
- "8000:8000"
volumes:
- woodpecker-server-data:/var/lib/woodpecker/
environment:
- WOODPECKER_OPEN=false
- WOODPECKER_HOST=https://ci.votre-domaine.com
- WOODPECKER_GITEA=true
- WOODPECKER_GITEA_URL=https://git.votre-domaine.com
- WOODPECKER_GITEA_CLIENT=${WOODPECKER_GITEA_CLIENT}
- WOODPECKER_GITEA_SECRET=${WOODPECKER_GITEA_SECRET}
- WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
woodpecker-agent:
image: woodpeckerci/woodpecker-agent:v3
restart: always
command: agent
depends_on:
- woodpecker-server
volumes:
- woodpecker-agent-config:/etc/woodpecker
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WOODPECKER_SERVER=woodpecker-server:9000
- WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
volumes:
woodpecker-server-data:
woodpecker-agent-config:Le serveur écoute en interne sur le port 8000 (interface web) et 9000 (gRPC, communication avec l'agent). N'exposez pas ces ports directement : un reverse proxy se charge du TLS.
Créer le fichier .env
Dans /opt/woodpecker, créez un fichier .env contenant les trois variables sensibles :
WOODPECKER_GITEA_CLIENT=<client-id-oauth2>
WOODPECKER_GITEA_SECRET=<client-secret-oauth2>
WOODPECKER_AGENT_SECRET=<chaine-aleatoire-longue>Générez WOODPECKER_AGENT_SECRET avec openssl rand -hex 32. Cette chaîne authentifie l'agent auprès du serveur — ne la partagez pas.
Configurer le reverse proxy nginx
Placez Woodpecker derrière nginx avec un certificat Let's Encrypt. Exemple de bloc server pour ci.votre-domaine.com :
server {
listen 443 ssl;
server_name ci.votre-domaine.com;
ssl_certificate /etc/letsencrypt/live/ci.votre-domaine.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ci.votre-domaine.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
}Obtenez le certificat avec certbot certonly --nginx -d ci.votre-domaine.com puis rechargez nginx avec systemctl reload nginx.
Démarrer la stack
Depuis /opt/woodpecker, lancez :
docker compose up -dSuivez les logs du serveur jusqu'à voir la ligne indiquant que le serveur est prêt :
docker compose logs -f woodpecker-serverOuvrez https://ci.votre-domaine.com dans votre navigateur. La page de connexion affiche un bouton Se connecter via Gitea. Cliquez dessus : Gitea demande l'autorisation OAuth2, puis vous redirige vers le dashboard Woodpecker.
Activer un dépôt et déclencher le premier build
Dans le dashboard Woodpecker, cliquez sur + Ajouter un dépôt. La liste de vos dépôts Gitea s'affiche. Sélectionnez un projet et activez-le. Woodpecker enregistre automatiquement un webhook dans Gitea pour déclencher les builds à chaque push.
Poussez un premier commit sur ce dépôt : si le fichier .woodpecker.yml est présent à la racine, le pipeline se déclenche immédiatement dans l'interface.
Migration d'un workflow GitHub Actions vers .woodpecker.yml
Woodpecker CI a sa propre syntaxe YAML — elle n'est pas compatible GitHub Actions. La bonne nouvelle : elle est plus courte. Voici la migration d'un workflow Node.js classique.
Avant — .github/workflows/ci.yml :
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm testAprès — .woodpecker.yml :
steps:
- name: test
image: node:20
commands:
- npm ci
- npm testLes différences clés : Woodpecker utilise directement une image Docker comme environnement d'exécution (pas besoin de setup-node), et chaque étape est déclarée comme un service de conteneur. L'action checkout est implicite — Woodpecker clone automatiquement le dépôt dans le workspace partagé entre les étapes.
Secrets de pipeline et variable WOODPECKER_SECRET
Ne mettez jamais de tokens, clés SSH ou mots de passe dans votre .woodpecker.yml versionné. Woodpecker gère les secrets au niveau du dépôt ou de l'organisation : dans le dashboard, ouvrez le dépôt → Paramètres → Secrets → Ajouter un secret. Chaque secret est injecté comme variable d'environnement au moment du build.
Pour utiliser un secret dans le pipeline :
steps:
- name: deploy
image: alpine
environment:
SSH_DEPLOY_KEY:
from_secret: ssh_deploy_key
commands:
- echo "$SSH_DEPLOY_KEY" > /tmp/id_rsa
- chmod 600 /tmp/id_rsa
- ssh -i /tmp/id_rsa [email protected] ./deploy.shLa syntaxe from_secret extrait la valeur depuis le coffre Woodpecker sans l'écrire dans les logs ni dans le fichier YAML.
Dépannage courant
L'agent n'apparaît pas dans le dashboard. Vérifiez que WOODPECKER_AGENT_SECRET est identique dans les deux services du docker-compose.yml. Si vous avez modifié le .env après le premier démarrage, relancez avec docker compose down && docker compose up -d.
La connexion OAuth2 échoue. L'URL de redirection enregistrée dans Gitea doit correspondre exactement à https://ci.votre-domaine.com/authorize. Une barre oblique finale, une faute d'orthographe ou un protocole HTTP au lieu de HTTPS suffisent à bloquer le flux OAuth2. Vérifiez également que WOODPECKER_GITEA_URL dans le docker-compose.yml pointe bien vers l'URL publique de votre Gitea — le conteneur Woodpecker doit pouvoir la résoudre depuis l'intérieur du réseau Docker.
Le webhook ne se déclenche pas. Ouvrez le dépôt dans Gitea → Paramètres → Webhooks et vérifiez que le webhook Woodpecker est bien présent et que les livraisons récentes n'ont pas d'erreur 4xx. Si l'URL de webhook pointe sur http:// au lieu de https://, Gitea peut refuser de l'appeler. Reconfigurez WOODPECKER_HOST avec l'URL complète en HTTPS et réactivez le dépôt dans Woodpecker pour forcer la mise à jour du webhook.
Les builds échouent par manque de mémoire. Le serveur et l'agent Woodpecker consomment moins de 50 Mo au repos — mais chaque étape de build lance un conteneur Docker supplémentaire. Sur un VPS à 1 Go, limitez les builds concurrents à 1 ou 2 en ajoutant WOODPECKER_MAX_PROCS=2 dans l'environnement du service woodpecker-agent.
Pour aller plus loin
Une fois le pipeline de base fonctionnel, plusieurs optimisations valent le détour.
Multi-runner. Ajoutez un second service woodpecker-agent dans votre docker-compose.yml (même image, même WOODPECKER_AGENT_SECRET) pour paralléliser les builds. Chaque agent est indépendant et peut tourner sur un VPS séparé si votre charge le justifie.
Cache Docker entre builds. Montez un volume Docker dans l'agent et activez le cache des layers Docker pour éviter de retélécharger les images à chaque build. Woodpecker supporte le cache de pipeline natif via le plugin woodpecker-ci/cache — ajoutez-le comme étape dédiée dans votre .woodpecker.yml.
Notifications. Woodpecker peut notifier un canal de messagerie à chaque build. Des plugins communautaires couvrent Matrix, Slack, Telegram et Mattermost — cherchez woodpecker-ci/notify-matrix ou appleboy/drone-telegram dans la documentation officielle.
Pipeline conditionnel. La syntaxe Woodpecker permet de restreindre une étape à une branche ou à un événement précis :
steps:
- name: deploy
image: alpine
when:
branch: main
event: push
commands:
- ./deploy.shPour approfondir la mise en place des pipelines, le guide Woodpecker CI et Forgejo : pipeline CI/CD sur VPS détaille les étapes avancées, notamment l'intégration Forgejo et les pipelines multi-étapes. Le guide Checklist Docker Compose en production couvre les bonnes pratiques pour sécuriser vos stacks Docker en production.