Montar Woodpecker CI Docker Compose te da integración continua propia en dos contenedores y unos 100 MB de RAM. Sin minutos que se agotan, sin cola compartida y sin que tu código salga de tu servidor. Si ya tienes tu forja Git en casa, este es el complemento natural.
Es una alternativa ligera a Jenkins y a los runners de GitHub Actions: sintaxis YAML muy parecida a la que ya conoces, pero sin una JVM ni un ecosistema de plugins que mantener.
Al terminar este artículo tendrás
- Servidor y agente funcionando y comunicados por gRPC.
- La conexión OAuth con tu forja Git configurada.
- Tu primer pipeline ejecutándose al hacer push.
- Secretos, HTTPS y varios agentes para escalar.
Qué es Woodpecker CI y por qué en Docker Compose
Woodpecker nació como un fork de Drone cuando este cambió de licencia, y hoy es un proyecto comunitario con licencia Apache 2.0. Su arquitectura tiene solo dos piezas, y entenderlas te ahorra el 90 % de los problemas de instalación.
| Componente | Función |
|---|---|
| Server | Interfaz web, autenticación contra la forja, cola de trabajos y base de datos. |
| Agent | Ejecuta los pasos del pipeline como contenedores. Puede haber varios. |
En Woodpecker CI Docker Compose ambos hablan por gRPC en el puerto 9000 usando un secreto compartido. El servidor no ejecuta nada: solo reparte. Esa separación es lo que permite tener el servidor en una máquina modesta y los agentes en otra con más músculo.
Frente a alternativas más pesadas, la ventaja de resolverlo con Woodpecker CI Docker Compose es el consumo: donde un servidor Jenkins te pide un par de gigas para estar cómodo, aquí te sobra con medio.
Frente a las alternativas
| Woodpecker | Jenkins | GitLab CI | |
|---|---|---|---|
| RAM en reposo | ~100 MB | 1-2 GB | 4 GB o más |
| Configuración | YAML en el repo | Groovy o interfaz | YAML en el repo |
| Extensiones | Plugins como imágenes | Catálogo enorme | Integrado |
| Curva | Baja | Alta | Media |
Lo interesante de la fila de extensiones: aquí un plugin no es un artefacto que instalas en el servidor y que puede romperte una actualización, sino simplemente una imagen de contenedor que se ejecuta en un paso. Eso elimina de un plumazo el problema clásico de mantenimiento de Jenkins, y es una de las razones de peso para montar Woodpecker CI Docker Compose en lugar de heredar una instalación pesada.
Requisitos previos de Woodpecker CI Docker Compose
- Una forja Git accesible: Forgejo, Gitea, GitHub o GitLab. Aquí usaremos Forgejo.
- Un dominio con HTTPS. No es opcional: OAuth necesita una URL de retorno estable.
- Docker Engine 24+ y unos 512 MB de RAM libres.
- El socket de Docker disponible para el agente.
Si aún no tienes forja propia, el punto de partida es el tutorial de Forgejo con Docker Compose; también funciona igual de bien con Gitea, que comparte el mismo origen.
Configurar Woodpecker CI Docker Compose paso a paso
Paso 1: registrar la aplicación OAuth
Esto va primero, porque de aquí salen los dos valores que necesitarás en el compose. En Forgejo entra en Configuración → Aplicaciones → Aplicaciones OAuth2 y crea una nueva. La URL de retorno tiene que ser exacta:
https://ci.midominio.es/authorize
Guarda el client ID y el client secret que te devuelve. Si prefieres que la integración sea de toda la instancia y no de tu usuario, créala desde Administración → Aplicaciones OAuth2.
Paso 2: generar el secreto de agente
Servidor y agente se autentican con una cadena compartida. Genera una de verdad, no pongas «cambiame».
mkdir -p ~/woodpecker && cd ~/woodpecker
openssl rand -hex 32
Copia el resultado al fichero de variables junto al resto de datos.
cat > .env <<'EOF'
WOODPECKER_HOST=https://ci.midominio.es
WOODPECKER_FORGEJO_URL=https://git.midominio.es
WOODPECKER_FORGEJO_CLIENT=pega-aqui-el-client-id
WOODPECKER_FORGEJO_SECRET=pega-aqui-el-client-secret
WOODPECKER_AGENT_SECRET=pega-aqui-el-openssl-rand
WOODPECKER_ADMIN=tuusuario
EOF
chmod 600 .env
Paso 3: escribir el docker-compose.yml
Este es el docker-compose.yml completo de Woodpecker CI Docker Compose, basado en el ejemplo oficial pero adaptado a Forgejo y con el registro público cerrado.
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:v3
container_name: woodpecker-server
restart: always
ports:
- "8000:8000"
volumes:
- ./server-data:/var/lib/woodpecker/
environment:
- WOODPECKER_OPEN=false
- WOODPECKER_ADMIN=${WOODPECKER_ADMIN}
- WOODPECKER_HOST=${WOODPECKER_HOST}
- WOODPECKER_FORGEJO=true
- WOODPECKER_FORGEJO_URL=${WOODPECKER_FORGEJO_URL}
- WOODPECKER_FORGEJO_CLIENT=${WOODPECKER_FORGEJO_CLIENT}
- WOODPECKER_FORGEJO_SECRET=${WOODPECKER_FORGEJO_SECRET}
- WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
woodpecker-agent:
image: woodpeckerci/woodpecker-agent:v3
container_name: woodpecker-agent
command: agent
restart: always
depends_on:
- woodpecker-server
volumes:
- ./agent-config:/etc/woodpecker
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WOODPECKER_SERVER=woodpecker-server:9000
- WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
- WOODPECKER_MAX_WORKFLOWS=2
Dos ajustes importantes respecto al ejemplo de la documentación. WOODPECKER_OPEN=false impide que cualquiera con cuenta en tu forja entre a la interfaz; sin eso, un servidor público se llena de desconocidos. Y WOODPECKER_MAX_WORKFLOWS limita cuántos trabajos ejecuta un agente en paralelo: dos es prudente para empezar.
Paso 4: levantar y verificar
docker compose up -d
docker compose logs -f woodpecker-agent
En los registros del agente debes ver que se conecta y queda a la espera. Si aparece un error de autenticación, el secreto no coincide entre ambos servicios: es el fallo número uno de esta instalación.
Advertencia: el socket de Docker
El agente monta /var/run/docker.sock, lo que equivale a darle control del host. Cualquiera que pueda escribir un pipeline en un repositorio conectado puede ejecutar lo que quiera en esa máquina. Conecta solo repositorios de confianza, y si vas a aceptar aportaciones externas, pon el agente en una máquina aislada.
Paso 5: publicar con HTTPS
OAuth no funciona en claro, así que necesitas un proxy inverso delante. Con Traefik y certificados automáticos son cinco etiquetas.
labels:
- "traefik.enable=true"
- "traefik.http.routers.woodpecker.rule=Host(`ci.midominio.es`)"
- "traefik.http.routers.woodpecker.entrypoints=websecure"
- "traefik.http.routers.woodpecker.tls.certresolver=letsencrypt"
- "traefik.http.services.woodpecker.loadbalancer.server.port=8000"
Si Forgejo corre en el mismo host, añade el agente a su misma red de Docker: el agente clona usando la URL que le devuelve la API de la forja, y si no la alcanza, los pipelines fallan en el primer paso.
Tu primer pipeline en Woodpecker CI Docker Compose
Con Woodpecker CI Docker Compose ya en marcha, entra en la interfaz, inicia sesión con tu forja y activa un repositorio. Después crea el fichero .woodpecker.yml en su raíz.
when:
- event: push
branch: main
steps:
- name: dependencias
image: node:22-alpine
commands:
- npm ci
- name: pruebas
image: node:22-alpine
commands:
- npm test
- name: construir imagen
image: woodpeckerci/plugin-docker-buildx
settings:
repo: git.midominio.es/miusuario/mi-app
registry: git.midominio.es
tags: latest
username:
from_secret: registro_usuario
password:
from_secret: registro_token
Cada paso corre en su propio contenedor y comparte el directorio de trabajo con los demás. La sintaxis resultará familiar si vienes de GitHub Actions, con la diferencia de que aquí eliges la imagen de cada paso explícitamente.
Los valores from_secret se definen en la configuración del repositorio dentro de la interfaz, nunca en el fichero. Puedes marcarlos para que no estén disponibles en pipelines de pull requests externas, que es justo lo que evita que alguien te robe las credenciales con un PR malicioso. El catálogo de plugins oficiales cubre despliegues, notificaciones y publicación de artefactos.
Secretos y matrices en Woodpecker CI Docker Compose
Dos funciones de Woodpecker CI Docker Compose que vas a necesitar en cuanto el pipeline pase de «hola mundo». La primera son los secretos, que se definen por repositorio, por organización o globales desde la interfaz, y nunca se escriben en el YAML.
| Ámbito | Cuándo usarlo |
|---|---|
| Repositorio | Credenciales de despliegue de un solo proyecto. |
| Organización | Token del registro de contenedores compartido. |
| Global | Notificaciones o claves comunes a toda la instancia. |
Al crear cada secreto eliges en qué eventos está disponible. Deja siempre desmarcado pull_request para los secretos con permisos de escritura: es la puerta clásica por la que se filtran credenciales desde una aportación externa.
La segunda función son las matrices, que multiplican un pipeline por cada combinación de valores. Muy útil para probar varias versiones de un lenguaje sin duplicar pasos.
matrix:
NODE_VERSION:
- 20
- 22
- 24
steps:
- name: pruebas
image: node:${NODE_VERSION}-alpine
commands:
- npm ci
- npm test
Eso lanza tres ejecuciones en paralelo, repartidas entre los agentes disponibles. Ojo con el consumo: una matriz de nueve combinaciones en un servidor con un solo agente y dos workflows simultáneos tarda lo que tarda. La referencia de sintaxis de workflows recoge el resto de opciones, incluidas las condiciones por rama, por ruta modificada y por resultado de pasos anteriores.
Escalar y mantener Woodpecker CI Docker Compose
Cuando la cola de Woodpecker CI Docker Compose empiece a acumularse, no toques el servidor: añade agentes. Basta con duplicar el bloque del agente con otro nombre, o llevarlo a otra máquina apuntando al mismo servidor.
- Base de datos. Por defecto usa SQLite en
/var/lib/woodpecker. Para varios agentes y uso intenso, pásate a PostgreSQL conWOODPECKER_DATABASE_DRIVER. - Limpieza. Los contenedores de pipeline dejan capas huérfanas; programa un
docker system prunesemanal en los agentes. - Copias. Respalda el volumen del servidor: ahí viven usuarios, secretos e historial. Los agentes son desechables.
- Actualizaciones. Sube servidor y agentes a la vez; versiones distintas pueden dejar de entenderse por gRPC.
Añadir un segundo agente
Crecer es literalmente copiar y pegar un bloque. El nuevo agente se registra solo contra el servidor en cuanto arranca con el secreto correcto, sin tocar nada en la interfaz.
woodpecker-agent-2:
image: woodpeckerci/woodpecker-agent:v3
container_name: woodpecker-agent-2
command: agent
restart: always
depends_on:
- woodpecker-server
volumes:
- ./agent2-config:/etc/woodpecker
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WOODPECKER_SERVER=woodpecker-server:9000
- WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
- WOODPECKER_MAX_WORKFLOWS=2
Fíjate en que cada agente necesita su propio directorio de configuración: ahí guarda su identificador tras registrarse, y si dos comparten volumen se pisan el uno al otro. Para llevarlo a otra máquina el cambio es sustituir woodpecker-server:9000 por la dirección real del servidor y abrir ese puerto entre ambas, preferiblemente por red privada o VPN y nunca expuesto a Internet.
Problemas frecuentes de Woodpecker CI Docker Compose
| Síntoma | Causa | Solución |
|---|---|---|
| El agente no conecta | Secreto distinto | Igualar WOODPECKER_AGENT_SECRET |
| Error OAuth al entrar | URL de retorno mal | Debe acabar en /authorize |
| Falla al clonar | El agente no ve la forja | Misma red Docker |
| El webhook no llega | Forja bloquea host local | ALLOWED_HOST_LIST=external,loopback |
| Pipelines en cola | Límite de workflows | Subir el valor o añadir agentes |
El cuarto es específico de Forgejo y Gitea: por seguridad no envían webhooks a direcciones internas salvo que se lo permitas expresamente en app.ini.
Hay un quinto problema que no cabe en la tabla porque su diagnóstico es más largo: pipelines que funcionan en tu portátil y fallan en el agente. Casi siempre es el directorio de trabajo. Cada paso arranca un contenedor nuevo y solo se comparte el volumen del repositorio clonado, así que todo lo que instales fuera de esa ruta desaparece al pasar al paso siguiente. Si un paso instala dependencias en /usr/local y el siguiente las necesita, no las encontrará.
La solución es usar la misma imagen en los pasos encadenados e instalar dentro del propio repositorio —node_modules, entornos virtuales de Python o similares—, o bien declarar un volumen de caché compartido. Comprobar esto primero te ahorra dar vueltas buscando fallos de permisos que no existen.
Conclusión sobre Woodpecker CI Docker Compose
Woodpecker CI Docker Compose no pretende competir con GitLab CI en funciones, y ahí está su gracia: hace lo que necesita el 90 % de los proyectos con una fracción de los recursos. Si tu equipo es pequeño y ya alojas tu propio Git, cierras el círculo completo —código, CI y registro de imágenes— en un único servidor modesto.
Empieza con Woodpecker CI Docker Compose conectando un solo repositorio con un pipeline de dos pasos y vete creciendo. Tienes el proyecto en su repositorio de GitHub, la guía de despliegue en la documentación oficial de Docker Compose, los detalles de la integración en la página de Forgejo y más ideas en los tutoriales de Docker Compose.
Preguntas frecuentes sobre Woodpecker CI Docker Compose
¿Sirve con GitHub o GitLab?
Sí. Cambia el bloque de variables por WOODPECKER_GITHUB o WOODPECKER_GITLAB con sus credenciales OAuth. Todo lo demás es idéntico, y puedes tener repositorios de varias forjas si levantas más de un servidor.
¿Cuánto consume realmente?
Servidor y agente en reposo rondan los 100 MB de RAM juntos. El consumo real lo marcan los contenedores de cada paso del pipeline, que es donde debes dimensionar la máquina.
¿Puedo migrar mis workflows de GitHub Actions?
No directamente, pero la traducción es mecánica: los jobs pasan a steps, cada uno con su image y sus commands. Lo que no existe es el catálogo de acciones de terceros; ahí usarás plugins o comandos a pelo.
¿Necesito un agente por proyecto?
No. Un agente atiende todos los repositorios y ejecuta tantos trabajos en paralelo como indique WOODPECKER_MAX_WORKFLOWS. Se añaden más agentes por capacidad, no por proyecto.
¿Es seguro exponerlo a Internet?
Con WOODPECKER_OPEN=false, HTTPS y administradores definidos, sí para un equipo. Ten presente siempre que el agente controla el host por el socket de Docker: la confianza que das a un repositorio conectado es total.
