Autoaloja Tu Git y CI/CD con Forgejo y Woodpecker CI
Configura una alternativa a GitHub autoalojada con Forgejo y CI/CD usando Woodpecker CI. Guia completa con Docker Compose en un VPS.
GitHub Actions esta bien hasta que ves la factura, te topas con los limites de tasa, o te das cuenta de que tu codigo se ejecuta en los servidores de otro. Si ya autoalojas tus aplicaciones en un VPS, alojar tu propio servidor Git y pipeline de CI/CD es el siguiente paso logico. Y es mas facil de lo que parece.
Esta guia explica como configurar Forgejo (un forge Git autoalojado) con CI/CD mediante Woodpecker CI. Forgejo gestiona tus repositorios, issues y pull requests. Woodpecker ejecuta tus builds, tests y despliegues. Juntos reemplazan a GitHub y GitHub Actions.
Por que no quedarse en GitHub?
Hay varias razones por las que la gente se muda:
- Control de costes: El tier gratuito de GitHub Actions se agota rapido en repositorios privados. Los runners autoalojados ayudan, pero sigues en la infraestructura de GitHub.
- Propiedad de los datos: Tu codigo, issues, pull requests y logs de CI viven en tu servidor. Sin sorpresas en los terminos de servicio.
- Desarrollo offline/local: Un VPS en tu region sin depender de la disponibilidad de GitHub.
- Lock-in de GitHub Actions: Cuantos mas workflows escribes, mas dificil es irse. Forgejo + Woodpecker mantiene la portabilidad.
Dicho esto, mucha gente mantiene un espejo en GitHub para el lado social del codigo. Puedes tener las dos cosas.
Forgejo vs Gitea: cual es la diferencia?
Forgejo se bifurco de Gitea en octubre de 2022 despues de que una empresa con fines de lucro se hiciera con el proyecto Gitea (dominios, marca, todo). La comunidad no fue consultada. Una carta abierta fue ignorada. Asi que hicieron un fork.
Desde 2024, Forgejo es un hard fork — los codigos base han divergido. Aqui van las diferencias:
| Forgejo | Gitea | |
|---|---|---|
| Gobierno | Sin fines de lucro (Codeberg e.V.) | Empresa con fines de lucro |
| Licencia | Exclusivamente Software Libre | Open Core (algunas features propietarias) |
| Desarrollado en | El propio Forgejo | GitHub |
| CI/CD testeado con | Forgejo Actions | GitHub Actions |
| Seguridad | Aviso previo para todos los usuarios | Aviso previo solo para clientes de pago |
| Federacion | Trabajando en soporte ActivityPub | Sin planes de federacion |
| Tests end-to-end | Si | No (a mediados de 2025) |
| Migracion desde Gitea | Soportada, mismo esquema de BD | N/A |
Funcionalmente son muy similares. Mismo UI, mismo formato de config, mismo Docker setup. Si empiezas de cero, ve con Forgejo. Si ya estas en Gitea y funciona bien, la migracion no es urgente — pero es un solo comando cuando estes listo.
Lo que necesitas
- Un VPS con al menos 2 GB de RAM (4 GB recomendado si ejecutas CI/CD en la misma maquina). Hetzner o Hostinger funcionan bien.
- Docker y Docker Compose instalados
- Un nombre de dominio (o subdominio) apuntando a tu VPS
- Comodidad basica con la terminal
Un solo VPS es suficiente
Todo en esta guia corre en un solo servidor. Forgejo, Woodpecker y el runner de CI pueden coexistir en un VPS de 4 GB sin problemas. Siempre puedes separarlos mas adelante.
Paso 1: Instalar Forgejo
Crea un directorio para Forgejo y prepara el Docker Compose:
mkdir -p /opt/forgejo && cd /opt/forgejo
Docker Compose
services:
forgejo:
image: codeberg.org/forgejo/forgejo:10
container_name: forgejo
environment:
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=sqlite3
- FORGEJO__server__DOMAIN=git.tudominio.com
- FORGEJO__server__ROOT_URL=https://git.tudominio.com
- FORGEJO__server__SSH_DOMAIN=git.tudominio.com
- FORGEJO__server__SSH_PORT=2222
- FORGEJO__server__SSH_LISTEN_PORT=22
- FORGEJO__service__DISABLE_REGISTRATION=true
- FORGEJO__actions__ENABLED=true
restart: unless-stopped
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
Un par de cosas a tener en cuenta:
- SSH en puerto 2222: El servidor SSH integrado de Forgejo usa el puerto 2222 para no entrar en conflicto con el SSH del sistema en el 22. Clonaras repos con
ssh://git@tudominio.com:2222/usuario/repo.git. - Registro deshabilitado: No quieres que cualquiera cree cuentas en tu servidor Git. Crea las cuentas manualmente o habilita el registro brevemente.
- SQLite: Sirve para equipos pequenos y uso personal. Si tienes 10+ usuarios, cambia a PostgreSQL.
Iniciar Forgejo
docker compose up -d
Visita https://git.tudominio.com, completa el asistente de configuracion inicial y crea tu cuenta de administrador.
Proxy inverso con Nginx
Si ejecutas Nginx en el host (no en Docker), anade un bloque de servidor:
server {
server_name git.tudominio.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/git.tudominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/git.tudominio.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
Obten el certificado primero:
certbot --nginx -d git.tudominio.com
Firewall
Asegurate de que los puertos 80, 443 y 2222 esten abiertos. Si usas UFW:
sudo ufw allow 'Nginx Full'
sudo ufw allow 2222 Paso 2: Instalar Woodpecker CI
Woodpecker es un servidor de CI/CD independiente que se conecta a Forgejo mediante OAuth. Es un fork comunitario de Drone CI, mantenido despues de que Drone cambiara su licencia. Cada paso del pipeline se ejecuta en su propio contenedor Docker, asi que tu entorno de build siempre esta limpio y reproducible.
Crear una aplicacion OAuth en Forgejo
- Ve a Administracion del Sitio → Aplicaciones (o a Configuracion de Usuario → Aplicaciones)
- Crea una nueva aplicacion OAuth2:
- Nombre: Woodpecker CI
- URI de Redireccion:
https://ci.tudominio.com/authorize
- Guarda el Client ID y el Client Secret
Docker Compose para Woodpecker
mkdir -p /opt/woodpecker && cd /opt/woodpecker
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:v3
container_name: woodpecker-server
restart: unless-stopped
ports:
- "8000:8000"
volumes:
- woodpecker_data:/var/lib/woodpecker
environment:
- WOODPECKER_OPEN=false
- WOODPECKER_HOST=https://ci.tudominio.com
- WOODPECKER_GITEA=true
- WOODPECKER_GITEA_URL=https://git.tudominio.com
- WOODPECKER_GITEA_CLIENT=TU_CLIENT_ID
- WOODPECKER_GITEA_SECRET=TU_CLIENT_SECRET
- WOODPECKER_AGENT_SECRET=TU_SECRETO_ALEATORIO
- WOODPECKER_DATABASE_DRIVER=sqlite3
- WOODPECKER_DATABASE_DATASOURCE=/var/lib/woodpecker/woodpecker.db
woodpecker-agent:
image: woodpeckerci/woodpecker-agent:v3
container_name: woodpecker-agent
restart: unless-stopped
depends_on:
- woodpecker-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WOODPECKER_SERVER=woodpecker-server:9000
- WOODPECKER_AGENT_SECRET=TU_SECRETO_ALEATORIO
- WOODPECKER_MAX_WORKFLOWS=2
volumes:
woodpecker_data:
Genera el secreto del agente:
openssl rand -hex 32
Usa el mismo secreto para ambas entradas de WOODPECKER_AGENT_SECRET.
Acceso al socket de Docker
El agente monta /var/run/docker.sock, lo que le da acceso completo al demonio Docker del host. Para un VPS de un solo usuario esto esta bien. Para entornos compartidos, considera usar Podman sin root o Kaniko.
Inicialo:
docker compose up -d
Anade un proxy inverso de Nginx para ci.tudominio.com igual que con Forgejo (proxy al puerto 8000).
Tu primer pipeline de Woodpecker
Crea .woodpecker.yml en la raiz de un repositorio en Forgejo:
pipeline:
build:
image: node:20-alpine
commands:
- npm ci
- npm run build
test:
image: node:20-alpine
commands:
- npm test
depends_on:
- build
deploy:
image: alpine:3.20
commands:
- apk add --no-cache openssh-client
- ssh -o StrictHostKeyChecking=no deploy@tuserver "cd /var/www/miapp && git pull && ./build.sh"
depends_on:
- test
when:
branch: main
Cada paso se ejecuta en su propio contenedor. El paso de deploy solo se ejecuta en la rama main.
Construir y subir imagenes Docker
Woodpecker tiene un plugin de Docker integrado:
pipeline:
build-image:
image: plugins/docker
settings:
repo: git.tudominio.com/tuusuario/miapp
registry: git.tudominio.com
tags:
- latest
- ${CI_COMMIT_SHA:0:8}
username:
from_secret: docker_username
password:
from_secret: docker_password
when:
branch: main
Anade los secretos mediante la UI o el CLI de Woodpecker:
woodpecker-cli secret add \
--repository tuusuario/miapp \
--name docker_username \
--value 'tuusuario'
woodpecker-cli secret add \
--repository tuusuario/miapp \
--name docker_password \
--value 'tu_token'
Paso 3: Configurar despliegues automaticos
Aqui va un patron del mundo real. Haces push al codigo, Woodpecker ejecuta los tests, y si pasan, la app se despliega en el mismo VPS.
El workflow de despliegue
El enfoque mas simple: conectarte por SSH al servidor, hacer pull del ultimo codigo, reconstruir.
Despliegues en el mismo servidor
Si Forgejo, CI y tu app corren en el mismo VPS, la conexion SSH es solo localhost. Parece redundante, pero mantiene tu workflow portable — cambia el destino SSH a otro servidor y todo sigue funcionando.
Con apps de Docker Compose
Si tu app corre en Docker Compose, el script de despliegue se complica un poco:
#!/bin/bash
cd /opt/miapp
git pull --force origin main
docker compose down
docker compose up -d --build
docker image prune -f
El flag --build reconstruye la imagen desde el Dockerfile. docker image prune limpia las imagenes viejas para que no se coman el espacio en disco.
Despliegues sin downtime
Para despliegues sin tiempo de inactividad, tienes algunas opciones segun tu stack:
- Swap de upstream en Nginx: Construye el nuevo contenedor en un puerto diferente, testalo, luego cambia el upstream de Nginx y recarga.
- Docker Compose con healthchecks: Define un healthcheck en tu compose file. Docker no enviara trafico hasta que el nuevo contenedor este healthy.
- Usar Kamal: Si quieres despliegues sin downtime sin escribir scripts, Kamal maneja esto de entrada. Es del equipo de Basecamp/Rails pero funciona con cualquier app Docker.
Paso 4: Registro de contenedores (opcional)
Forgejo tiene un registro de contenedores integrado. Hablitalo en app.ini:
[packages]
ENABLED=true
Luego sube imagenes a git.tudominio.com/tuusuario/miapp:tag desde tu pipeline de CI. El plugin Docker de Woodpecker maneja esto sin problemas.
Esto te ahorra ejecutar un registro Docker separado o pagar por Docker Hub.
Por que Woodpecker y no otra cosa?
Forgejo en realidad tiene un sistema de CI integrado tambien (Forgejo Actions, compatible con la sintaxis de GitHub Actions). Entonces, por que molestarse en instalar Woodpecker por separado?
Algunas razones:
- UI dedicada: Woodpecker tiene su propia interfaz web para monitorear builds, ver logs y gestionar secretos. Es mas limpio que meter CI dentro de la UI de Forgejo.
- Matrix builds: Ejecuta el mismo pipeline con multiples versiones de Node, Python o lo que sea. Woodpecker lo maneja de forma nativa.
- Limites de recursos por paso: Caps de CPU y memoria por paso del pipeline para que un build no se coma los recursos del resto del servidor.
- Soporte multi-forge: Si tambien tienes repos en GitHub o GitLab, Woodpecker puede conectarse a todos. No estas atado a un proveedor Git.
- Ecosistema de plugins: El sistema de plugins de Woodpecker esta pensado para CI/CD. Builds de imagenes Docker, notificaciones a Slack, subida de artefactos a S3 — todo de primera clase.
Si vienes de GitHub y solo quieres copiar tus archivos de .github/workflows con cambios minimos, Forgejo Actions es el camino mas simple. Pero si estas configurando CI/CD desde cero y quieres algo robusto, Woodpecker es la mejor herramienta.
Copias de seguridad
No te saltes esta parte. Tu servidor Git es la fuente de verdad de todos tus proyectos.
#!/bin/bash
DATE=$(date +%Y-%m-%d)
BACKUP_DIR="/home/backups/forgejo"
# Detener Forgejo para una copia consistente
cd /opt/forgejo && docker compose stop
# Crear archivo comprimido
tar -czf "$BACKUP_DIR/forgejo-$DATE.tar.gz" -C /opt/forgejo/data .
# Reiniciar Forgejo
docker compose up -d
# Encriptar
gpg --encrypt --armor -r tu@email.com \
-o "$BACKUP_DIR/forgejo-$DATE.tar.gz.gpg" \
"$BACKUP_DIR/forgejo-$DATE.tar.gz"
# Eliminar copia sin encriptar
rm "$BACKUP_DIR/forgejo-$DATE.tar.gz"
Ejecutalo cada noche con cron. Copia las copias encriptadas fuera del servidor (rsync a un NAS, rclone a S3, lo que te funcione).
Para Woodpecker, haz copia del volumen woodpecker_data de la misma manera.
El panorama completo
Asi se ve la configuracion completa en un solo VPS:
/opt/
├── forgejo/
│ ├── docker-compose.yml
│ └── data/ # Datos de Forgejo + SQLite DB
├── woodpecker/
│ ├── docker-compose.yml
│ └── ...
├── miapp/
│ ├── docker-compose.yml
│ └── ...
└── otra-app/
└── docker-compose.yml
Push a Forgejo → CI ejecuta tests → despliega en el mismo servidor → Nginx lo sirve. Coste total: un VPS, unos 7-15 EUR/mes.
Sin facturas de GitHub. Sin sorpresas de Vercel. Tu codigo, tu servidor, tus reglas.
Problemas comunes
Conflictos de puerto SSH: El SSH de Forgejo corre en el puerto 2222 por defecto. Asegurate de que tu firewall lo permita y que las URLs de clonado incluyan el puerto.
El agente no recoge trabajos: Revisa los logs del agente con docker compose logs woodpecker-agent. Asegurate de que WOODPECKER_AGENT_SECRET coincida entre servidor y agente.
Permisos del socket de Docker: Si el runner de CI no puede acceder a Docker, verifica que el contenedor tenga /var/run/docker.sock montado y que el usuario tenga permisos de Docker.
Espacio en disco: Los runners de CI generan muchas imagenes Docker con el tiempo. Anade un cron job para limpiar imagenes viejas:
0 3 * * * docker system prune -af --filter "until=72h"
Esto elimina imagenes sin usar de mas de 3 dias.