Gitea es una plataforma Git autoalojada y ligera con incidencias, pull requests y un sistema de CI/CD integrado, Gitea Actions, compatible con la sintaxis de GitHub Actions. En este tutorial partirás de una instalación de Gitea ya funcionando en Ubuntu 24.04 y añadirás lo que la convierte en una plataforma de equipo: un runner act_runner para ejecutar pipelines en contenedores Docker, un workflow de ejemplo, autenticación LDAP, repositorios espejo y copias de seguridad diarias automatizadas.
Requisitos previos
Para seguir esta guía necesitas:
- Gitea 1.21 o posterior instalado con el binario oficial en Ubuntu 24.04, con la disposición de la documentación de Gitea: binario en
/usr/local/bin/gitea, configuración en/etc/gitea/app.ini, datos en/var/lib/giteay usuario del sistemagit. Si usas otras rutas, adáptalas en los comandos. - Gitea publicado con HTTPS en un dominio, en la guía
git.your_domain. - Una cuenta de administrador en Gitea.
- Docker Engine instalado en la máquina del runner (puede ser el mismo servidor, por ejemplo un VPS de CubePath con al menos 4 GB de RAM, o uno dedicado a CI).
- Un usuario no root con privilegios
sudo.
Paso 1: Comprobar que Gitea Actions está activado
Desde Gitea 1.21, Actions está activado por defecto. Comprueba que no se ha desactivado en la configuración:
sudo grep -A2 '^\[actions\]' /etc/gitea/app.ini
Si el comando no devuelve nada, se usa el valor por defecto y Actions está activo. Si ves ENABLED = false, cámbialo a true y reinicia Gitea con sudo systemctl restart gitea.
Para confirmarlo en la interfaz, entra como administrador en Administración del sitio: debe aparecer la sección Actions > Runners.
Paso 2: Instalar act_runner
act_runner es el runner oficial de Gitea. Recibe trabajos de la instancia y los ejecuta en contenedores Docker. Consulta la última versión estable en https://dl.gitea.com/act_runner/ y guárdala en una variable:
RUNNER_VERSION=0.2.13
Descarga el binario para tu arquitectura (amd64 o arm64) e instálalo:
curl -fL -o act_runner "https://dl.gitea.com/act_runner/${RUNNER_VERSION}/act_runner-${RUNNER_VERSION}-linux-amd64"
sudo install -m 0755 act_runner /usr/local/bin/act_runner
act_runner --version
act_runner version v0.2.13
Crea un usuario de sistema propio para el runner y añádelo al grupo docker, ya que lanzará contenedores:
sudo useradd --system --create-home --home-dir /var/lib/act_runner --shell /usr/sbin/nologin act_runner
sudo usermod -aG docker act_runner
Advertenciapertenecer al grupo
dockerequivale en la práctica a tener acceso root en la máquina. Por eso el runner tiene su propio usuario y conviene usarlo solo con repositorios de confianza.
Genera la configuración por defecto en /etc/act_runner:
sudo mkdir -p /etc/act_runner
act_runner generate-config | sudo tee /etc/act_runner/config.yaml > /dev/null
El fichero generado está comentado. Los valores por defecto sirven para empezar; el más relevante es runner.capacity, el número de trabajos simultáneos (1 por defecto).
Paso 3: Registrar el runner
En Gitea, ve a Administración del sitio > Actions > Runners > Crear nuevo runner y copia el token de registro. Un runner registrado ahí sirve a toda la instancia; si prefieres uno por organización o repositorio, obtén el token en sus ajustes de Actions.
Registra el runner como el usuario act_runner y desde su directorio de trabajo, porque el registro crea ahí el fichero .runner con sus credenciales. Sustituye your_registration_token:
sudo -u act_runner sh -c 'cd /var/lib/act_runner && act_runner register \
--no-interactive \
--config /etc/act_runner/config.yaml \
--instance https://git.your_domain \
--token your_registration_token \
--name runner-01 \
--labels ubuntu-latest:docker://gitea/runner-images:ubuntu-latest'
INFO Registering runner, arch=amd64, os=linux, version=v0.2.13.
INFO Runner registered successfully.
La etiqueta ubuntu-latest:docker://gitea/runner-images:ubuntu-latest significa que los trabajos con runs-on: ubuntu-latest se ejecutarán en un contenedor de esa imagen, que incluye Node.js y las herramientas habituales de las acciones de GitHub.
Paso 4: Ejecutar el runner como servicio
Crea la unidad de systemd:
sudo nano /etc/systemd/system/act_runner.service
[Unit]
Description=Gitea Actions runner
Documentation=https://gitea.com/gitea/act_runner
After=docker.service
Requires=docker.service
[Service]
ExecStart=/usr/local/bin/act_runner daemon --config /etc/act_runner/config.yaml
ExecReload=/bin/kill -s HUP $MAINPID
WorkingDirectory=/var/lib/act_runner
User=act_runner
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Actívala y revisa el registro:
sudo systemctl daemon-reload
sudo systemctl enable --now act_runner
sudo journalctl -u act_runner -n 10 --no-pager
INFO Starting runner daemon
INFO runner: runner-01, with version: v0.2.13, with labels: [ubuntu-latest], declare successfully
En Administración del sitio > Actions > Runners, runner-01 debe aparecer con estado Idle.
Paso 5: Crear un pipeline CI/CD
Los workflows se guardan en .gitea/workflows/ dentro del repositorio. Si el repositorio es nuevo, activa Actions en Ajustes del repositorio > Unidades > Actions.
Este ejemplo para un proyecto Node.js ejecuta las pruebas en cada push y pull request, y despliega por SSH solo cuando el push llega a main:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm ci
- run: npm test
deploy:
needs: test
if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Desplegar por SSH
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
install -m 700 -d ~/.ssh
echo "$DEPLOY_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts
ssh deploy@"$DEPLOY_HOST" 'cd /srv/app && git pull && docker compose up -d --build'
Guárdalo como .gitea/workflows/ci.yml. Gitea descarga actions/checkout y actions/setup-node desde GitHub por defecto, así que el runner necesita salida a Internet.
Crea los secretos DEPLOY_HOST (IP o nombre del servidor de destino) y DEPLOY_KEY (clave privada SSH de un usuario deploy con acceso limitado) en Ajustes del repositorio > Actions > Secretos. Los secretos no se muestran en los registros de los trabajos.
Haz commit y push, y abre la pestaña Actions del repositorio. Verás la ejecución con sus dos trabajos; un círculo verde en cada uno indica que terminó correctamente.
Paso 6: Notificar eventos con webhooks
Los webhooks avisan a servicios externos (Slack, Discord, Matrix, Telegram o una URL propia) cuando ocurre algo en el repositorio. Gitea incluye formatos nativos para los principales servicios de chat, así que no necesitas scripts intermedios.
Ve a Ajustes del repositorio > Webhooks > Añadir webhook, elige el tipo (por ejemplo Discord o Slack), pega la URL de entrada que te da ese servicio y selecciona los eventos, como Push o Pull request. Para un webhook de tipo Gitea hacia tu propia aplicación, rellena también Secreto: Gitea firmará cada petición con HMAC-SHA256 en la cabecera X-Gitea-Signature, que tu aplicación debe verificar.
Tras guardarlo, pulsa Probar entrega. En Entregas recientes verás la petición enviada y el código de respuesta; un 200 o 204 confirma que llega.
Paso 7: Conectar Gitea con LDAP o Active Directory
Con LDAP, los usuarios inician sesión en Gitea con sus credenciales corporativas y la cuenta se crea en el primer acceso. Antes de configurar Gitea, comprueba desde el servidor que la cuenta de servicio puede buscar usuarios. Instala el cliente y lanza una búsqueda de prueba (te pedirá la contraseña de la cuenta de enlace):
sudo apt install ldap-utils
ldapsearch -x -H ldaps://ldap.your_domain -D "cn=gitea-bind,ou=Servicios,dc=example,dc=com" -W -b "ou=Usuarios,dc=example,dc=com" "(sAMAccountName=usuario_prueba)" mail
Si devuelve el usuario con su atributo mail, añade la fuente de autenticación con la CLI de Gitea, ejecutada como el usuario git. Este ejemplo es para Active Directory por LDAPS; en OpenLDAP usa uid en lugar de sAMAccountName:
sudo -u git gitea admin auth add-ldap \
--config /etc/gitea/app.ini \
--work-path /var/lib/gitea \
--name "Active Directory" \
--security-protocol LDAPS \
--host ldap.your_domain \
--port 636 \
--bind-dn "cn=gitea-bind,ou=Servicios,dc=example,dc=com" \
--bind-password 'your_bind_password' \
--user-search-base "ou=Usuarios,dc=example,dc=com" \
--user-filter "(&(objectClass=user)(sAMAccountName=%s))" \
--username-attribute sAMAccountName \
--firstname-attribute givenName \
--surname-attribute sn \
--email-attribute mail
Comprueba que la fuente existe:
sudo -u git gitea admin auth list --config /etc/gitea/app.ini --work-path /var/lib/gitea
ID Name Type Enabled
1 Active Directory LDAP (via BindDN) true
Cierra sesión e inicia sesión con un usuario del directorio. La fuente se puede editar después en Administración del sitio > Fuentes de autenticación.
Paso 8: Crear repositorios espejo
Un espejo (mirror) es una copia de solo lectura de un repositorio externo que Gitea sincroniza periódicamente. Es útil para tener una copia local de dependencias o de proyectos alojados en GitHub.
Desde la interfaz, usa + > Nueva migración, elige el origen y marca Este repositorio será un espejo. Para automatizarlo, usa la API. Crea antes un token de acceso en Configuración > Aplicaciones con permiso de escritura sobre repositorios y sustituye your_api_token y your_user:
curl -fsS -X POST "https://git.your_domain/api/v1/repos/migrate" \
-H "Authorization: token your_api_token" \
-H "Content-Type: application/json" \
-d '{
"clone_addr": "https://github.com/go-gitea/gitea.git",
"repo_name": "gitea-mirror",
"repo_owner": "your_user",
"mirror": true,
"mirror_interval": "8h0m0s",
"private": true
}'
La respuesta es el JSON del repositorio creado con "mirror": true. Para forzar una sincronización sin esperar al intervalo:
curl -fsS -X POST "https://git.your_domain/api/v1/repos/your_user/gitea-mirror/mirror-sync" \
-H "Authorization: token your_api_token"
Paso 9: Automatizar copias de seguridad con gitea dump
gitea dump genera un único fichero con los repositorios, la base de datos exportada, la configuración y los datos adjuntos. Crea un directorio para las copias, propiedad del usuario git:
sudo install -d -o git -g git -m 750 /var/backups/gitea
Crea el script de copia:
sudo nano /usr/local/bin/gitea-backup
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/var/backups/gitea"
KEEP_DAYS=7
STAMP="$(date +%Y%m%d-%H%M%S)"
cd "$BACKUP_DIR"
/usr/local/bin/gitea dump \
--config /etc/gitea/app.ini \
--work-path /var/lib/gitea \
--tempdir "$BACKUP_DIR" \
--skip-log \
--file "$BACKUP_DIR/gitea-dump-$STAMP.zip"
find "$BACKUP_DIR" -maxdepth 1 -name 'gitea-dump-*.zip' -mtime +"$KEEP_DAYS" -delete
Hazlo ejecutable y pruébalo como el usuario git:
sudo chmod 755 /usr/local/bin/gitea-backup
sudo -u git /usr/local/bin/gitea-backup
sudo ls -lh /var/backups/gitea
-rw------- 1 git git 148M Sep 25 12:40 gitea-dump-20260925-124002.zip
Prográmalo cada noche con un temporizador de systemd. Primero el servicio:
sudo nano /etc/systemd/system/gitea-backup.service
[Unit]
Description=Copia de seguridad de Gitea
[Service]
Type=oneshot
User=git
ExecStart=/usr/local/bin/gitea-backup
Después el temporizador:
sudo nano /etc/systemd/system/gitea-backup.timer
[Unit]
Description=Copia diaria de Gitea
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
Actívalo y comprueba la próxima ejecución:
sudo systemctl daemon-reload
sudo systemctl enable --now gitea-backup.timer
systemctl list-timers gitea-backup.timer
Importanteuna copia en el mismo disco no protege frente a la pérdida del servidor. Copia los ficheros de
/var/backups/giteaa otro sistema o a almacenamiento de objetos.
Solución de problemas
El runner aparece como Offline. Revisa sudo journalctl -u act_runner -n 50 --no-pager. Si ves errores de conexión, comprueba desde la máquina del runner que la URL responde con curl -I https://git.your_domain. Si el error es de permisos sobre /var/run/docker.sock, confirma que act_runner está en el grupo docker y reinicia el servicio.
Los trabajos quedan en espera ("Waiting"). Ningún runner tiene la etiqueta del runs-on. Compara las etiquetas del runner en la lista de runners con las del workflow.
Los usuarios LDAP no pueden iniciar sesión. Repite la búsqueda con ldapsearch sustituyendo %s por el usuario real. Si falla con LDAPS, comprueba que el servidor confía en el certificado del controlador de dominio.
gitea dump falla por permisos. Ejecútalo siempre como git; con otro usuario no puede leer /var/lib/gitea ni /etc/gitea/app.ini.
Conclusión
Tu instancia de Gitea ya ejecuta pipelines CI/CD con un runner propio en Docker, autentica contra el directorio corporativo, mantiene espejos de repositorios externos y guarda una copia diaria con rotación de 7 días. Como siguientes pasos, puedes añadir más runners con etiquetas distintas (por ejemplo arm64), activar el registro de paquetes y contenedores integrado de Gitea para publicar artefactos desde los workflows y practicar la restauración de una copia en un servidor de pruebas.
