GitHub y la tarificación de runners: lo que ocurrió en 2025-2026
Hasta 2025, los repositorios privados tenían una cuota mensual de minutos incluidos. El 16 de diciembre de 2025, GitHub anunció precios por minuto para el uso de runners — incluidos los self-hosted runners que corren en tus propias máquinas. La discusión de GitHub #182089 (diciembre de 2025, 72 votos) resume la preocupación: los equipos habrían pagado a GitHub por orquestar un trabajo corriendo en su propia infraestructura, a 0,002 $ por minuto.
Ante una reacción masiva de la comunidad, GitHub suspendió la tarificación en menos de 48 horas. A 1 de septiembre de 2026, los runners self-hosted en repos privados siguen siendo gratuitos — la medida nunca llegó a aplicarse. Pero el anuncio dejó al descubierto una dependencia estructural: GitHub puede cambiar sus condiciones en cualquier momento. Trasladar toda la cadena CI/CD a una forja self-hosted es la manera de eliminar esa incertidumbre. Woodpecker CI está diseñado exactamente para esto: un motor de pipeline ligero, open source (Apache 2.0), que se instala junto a Gitea o Forgejo y no tiene contador de minutos.
GitHub Actions runners vs Woodpecker CI self-hosted
Desplace la tabla
| Criterio | GitHub Actions (runners cloud) | Woodpecker CI en VPS |
|---|---|---|
| Coste | 0,008 $ / min (Linux) + 0,002 $ / min orquestación en repos privados | Incluido en el coste fijo del VPS (desde `{{vps.start.price}}`) |
| RAM del motor CI | Runners GitHub-hosted: recursos compartidos, no controlados | Servidor + agente Woodpecker: menos de 50 MB RAM combinados |
| Soberanía | El código y los secretos pasan por la infraestructura de GitHub/Microsoft | Todo permanece en tu VPS — sin tránsito externo |
| Sintaxis de workflow | `.github/workflows/*.yml` — estándar muy extendido | `.woodpecker.yml` — sintaxis propia, más corta, no compatible con GitHub Actions |
| Forja requerida | Ninguna (GitHub aloja el repositorio) | Gitea o Forgejo self-hosted |
| Licencia | Propietaria | Apache 2.0 |
Requisitos previos antes de la instalación
Para desplegar Woodpecker CI cómodamente, verifica los siguientes requisitos.
VPS: 1 vCPU y 1 GB de RAM son suficientes para el servidor Woodpecker, un agente y una forja Gitea o Forgejo ligera. Cuenta con 2 GB si ejecutas varios builds en paralelo o tus jobs construyen imágenes Docker.
Software: Docker y Docker Compose deben estar instalados. Si partes de un VPS limpio, la guía Empezar con Docker en VPS cubre este paso.
Forja git: Woodpecker CI utiliza OAuth2 para la autenticación. Necesitas una instancia de Gitea o Forgejo ya en marcha y accesible vía HTTPS. Las guías Alojar Gitea y Alojar Forgejo detallan esta instalación.
Dominio: prepara un subdominio dedicado para Woodpecker — por ejemplo ci.tu-dominio.com — apuntando a la IP de tu VPS con el puerto 443 abierto. Este subdominio sirve como WOODPECKER_HOST y como URL de redirección OAuth2.
Instalar Woodpecker CI con Docker Compose
Crear una aplicación OAuth2 en Gitea
En Gitea, ve a Configuración → Aplicaciones → Gestionar aplicaciones OAuth2. Da un nombre a la aplicación (por ejemplo
woodpecker) e introduce la URL de redirección:https://ci.tu-dominio.com/authorize. Anota el Client ID y el Client Secret generados — los necesitarás en el paso siguiente.Si usas Forgejo, el procedimiento es idéntico: Configuración → Aplicaciones → OAuth2.
Crear el archivo docker-compose.yml
Crea el directorio
/opt/woodpeckery coloca en él un archivodocker-compose.ymlcon los dos servicios — servidor y agente: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.tu-dominio.com - WOODPECKER_GITEA=true - WOODPECKER_GITEA_URL=https://git.tu-dominio.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:El servidor escucha internamente en el puerto 8000 (interfaz web) y 9000 (gRPC, comunicación con el agente). No expongas estos puertos directamente: un proxy inverso gestiona el TLS.
Crear el archivo .env
En
/opt/woodpecker, crea un archivo.envcon las tres variables sensibles:WOODPECKER_GITEA_CLIENT=<oauth2-client-id> WOODPECKER_GITEA_SECRET=<oauth2-client-secret> WOODPECKER_AGENT_SECRET=<cadena-aleatoria-larga>Genera
WOODPECKER_AGENT_SECRETconopenssl rand -hex 32. Esta cadena autentica al agente con el servidor — no la compartas.Configurar el proxy inverso nginx
Coloca Woodpecker detrás de nginx con un certificado Let's Encrypt. Ejemplo de bloque
serverparaci.tu-dominio.com:server { listen 443 ssl; server_name ci.tu-dominio.com; ssl_certificate /etc/letsencrypt/live/ci.tu-dominio.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ci.tu-dominio.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; } }Obtén el certificado con
certbot certonly --nginx -d ci.tu-dominio.comy recarga nginx consystemctl reload nginx.Arrancar la stack
Desde
/opt/woodpecker, ejecuta:docker compose up -dSigue los logs del servidor hasta ver la línea de listo:
docker compose logs -f woodpecker-serverAbre
https://ci.tu-dominio.comen tu navegador. La página de inicio de sesión muestra un botón Iniciar sesión con Gitea. Haz clic: Gitea solicita autorización OAuth2 y te redirige al dashboard de Woodpecker.Activar un repositorio y lanzar el primer build
En el dashboard de Woodpecker, haz clic en + Añadir repositorio. Aparece tu lista de repositorios Gitea. Selecciona un proyecto y actívalo. Woodpecker registra automáticamente un webhook en Gitea para lanzar builds en cada push.
Realiza un primer commit en ese repositorio: si el archivo
.woodpecker.ymlestá en la raíz, el pipeline se dispara inmediatamente en la interfaz.
Migrar un workflow de GitHub Actions a .woodpecker.yml
Woodpecker CI tiene su propia sintaxis YAML — no es compatible con GitHub Actions. La buena noticia: es más corta. Aquí tienes la migración de un workflow clásico de Node.js.
Antes — .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 testDespués — .woodpecker.yml:
steps:
- name: test
image: node:20
commands:
- npm ci
- npm testDiferencias clave: Woodpecker usa directamente una imagen Docker como entorno de ejecución (no necesita setup-node), y cada paso es un servicio de contenedor. La acción checkout es implícita — Woodpecker clona automáticamente el repositorio en el espacio de trabajo compartido entre los pasos.
Secretos de pipeline y la variable WOODPECKER_SECRET
Nunca pongas tokens, claves SSH ni contraseñas en tu .woodpecker.yml versionado. Woodpecker gestiona los secretos a nivel de repositorio u organización: en el dashboard, abre el repositorio → Configuración → Secretos → Añadir secreto. Cada secreto se inyecta como variable de entorno en tiempo de build.
Para usar un secreto en el 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 sintaxis from_secret extrae el valor del almacén de Woodpecker sin escribirlo en los logs ni en el archivo YAML.
Resolución de problemas habituales
El agente no aparece en el dashboard. Verifica que WOODPECKER_AGENT_SECRET sea idéntico en ambos servicios del docker-compose.yml. Si modificaste el .env después del primer arranque, reinicia con docker compose down && docker compose up -d.
El inicio de sesión OAuth2 falla. La URL de redirección registrada en Gitea debe coincidir exactamente con https://ci.tu-dominio.com/authorize. Una barra final, un error tipográfico o HTTP en lugar de HTTPS son suficientes para bloquear el flujo OAuth2. Comprueba también que WOODPECKER_GITEA_URL apunte a la URL pública de tu Gitea.
El webhook no se dispara. Abre el repositorio en Gitea → Configuración → Webhooks y verifica que el webhook de Woodpecker esté presente y que las entregas recientes no tengan errores 4xx.
Los builds fallan por falta de memoria. El servidor y el agente de Woodpecker consumen menos de 50 MB en reposo — pero cada paso de build lanza un contenedor Docker adicional. En un VPS de 1 GB, limita los builds concurrentes añadiendo WOODPECKER_MAX_PROCS=2 al entorno del servicio woodpecker-agent.
Para ir más lejos
Una vez que el pipeline base funciona, varias optimizaciones valen la pena.
Multi-runner. Añade un segundo servicio woodpecker-agent a tu docker-compose.yml (misma imagen, mismo WOODPECKER_AGENT_SECRET) para paralelizar los builds.
Caché Docker entre builds. Monta un volumen Docker en el agente y activa la caché de capas Docker para evitar volver a descargar las imágenes en cada build.
Notificaciones. Woodpecker puede notificar un canal de mensajería en cada build — Matrix, Slack, Telegram y Mattermost.
Pipeline condicional. La sintaxis de Woodpecker permite restringir un paso a una rama o evento concreto:
steps:
- name: deploy
image: alpine
when:
branch: main
event: push
commands:
- ./deploy.shPara profundizar en la configuración de pipelines, la guía Woodpecker CI y Forgejo: pipeline CI/CD en VPS detalla los pasos avanzados.