Ir al contenido
  1. Posts/

Forgejo: tu propio GitHub self-hosted sin las limitaciones de Gitea

Tengo un servidor de Gitea funcionando desde hace tiempo. Lo usé durante años para alojar código personal, scripts del homelab, y configuraciones. Cuando apareció Forgejo como fork de Gitea, al principio lo ignoré. Otro fork más. Luego fui leyendo más sobre el tema y terminé migrando.

La historia es la siguiente: en 2022, los mantenedores principales de Gitea crearon una empresa, Gitea Ltd., que asumió el control del proyecto y de la marca. Parte de la comunidad de contribuidores lo vio como un cambio de gobernanza problemático, crearon un fork llamado Forgejo bajo la Software Freedom Conservancy para mantener el proyecto gobernado por la comunidad de forma transparente. El código inicial es el mismo, pero los caminos están divergiendo.

Desde entonces Forgejo ha añadido cosas que Gitea no tiene, como Forgejo Actions (compatible con la sintaxis de GitHub Actions) y un sistema de federación ActivityPub que permite seguir repositorios entre instancias diferentes. La base es la misma, la instalación es casi idéntica, y la migración desde Gitea es directa.

Si estás empezando desde cero, te recomiendo Forgejo. Si tienes Gitea y estás contento, es una decisión más matizada, pero la migración no es dolorosa.

Qué ofrece Forgejo
#

Repositorios git privados y públicos, igual que GitHub. Interfaz web para navegar código, ver commits, abrir issues, gestionar pull requests. Wikis por repositorio. Sistema de releases con adjuntos. Packages para alojar paquetes npm, PyPI, Docker, Helm, y otros formatos.

Forgejo Actions es la parte que más me interesa ahora mismo. Funciona con la misma sintaxis de los workflows de GitHub Actions. Si tienes pipelines de CI/CD en GitHub, puedes moverlos a Forgejo con cambios mínimos o ninguno. No hay que aprender una nueva sintaxis.

El runner de Forgejo Actions es un proceso aparte que se registra contra tu instancia de Forgejo y ejecuta los jobs. Puedes tener runners en diferentes máquinas, lo que te permite correr pipelines en el hardware que quieras.

Instalación con Docker Compose
#

La instalación más limpia es con Docker Compose. Uso PostgreSQL como base de datos porque es más robusto que SQLite para uso con múltiples usuarios o proyectos activos, aunque para uso personal SQLite funciona perfectamente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
version: "3"
services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:9
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - FORGEJO__database__DB_TYPE=postgres
      - FORGEJO__database__HOST=db:5432
      - FORGEJO__database__NAME=forgejo
      - FORGEJO__database__USER=forgejo
      - FORGEJO__database__PASSWD=contraseña-db
    restart: unless-stopped
    volumes:
      - ./forgejo:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:22"
    depends_on:
      - db

  db:
    image: postgres:16
    container_name: forgejo-db
    restart: unless-stopped
    environment:
      - POSTGRES_USER=forgejo
      - POSTGRES_PASSWORD=contraseña-db
      - POSTGRES_DB=forgejo
    volumes:
      - ./forgejo-db:/var/lib/postgresql/data

El puerto 3000 es la interfaz web. El 2222 es para SSH git (clonar con git clone ssh://git@tu-servidor:2222/usuario/repo.git). Puedes cambiarlos si necesitas.

Cuando levantas el contenedor y abres la interfaz web por primera vez, te lleva a una pantalla de configuración inicial. Ahí defines la URL base, el nombre de la instancia, configuras el servidor de email si lo tienes, y creas el usuario administrador. Guarda esa configuración en ./forgejo/gitea/conf/app.ini.

Uno de los ajustes importantes en la configuración inicial es desactivar el registro público si no quieres que nadie más se registre:

1
2
[service]
DISABLE_REGISTRATION = true

También puedes hacerlo desde el panel de administración de la web después de crear tu usuario.

Primeros pasos: organizar los repositorios
#

Forgejo tiene el mismo modelo que GitHub: usuarios y organizaciones. Los repositorios pertenecen a uno u otro.

Para uso personal, creo repositorios directamente en mi usuario. Para proyectos con varias personas o con separación clara por tema, uso organizaciones. Tengo una organización para el homelab con todos los repositorios de configuración y scripts, y otra para proyectos de desarrollo.

Crear una organización es desde el menú de usuario, “Create Organization”. Le das un nombre, decides si los repositorios son privados por defecto, y añades miembros. Los miembros pueden tener roles diferentes: Owner, Manager, Developer, Reporter.

Para importar un repositorio existente de GitHub, GitLab, o Gitea, Forgejo tiene una opción de migración. En “New Repository” tienes la opción “Migrate”. Le das la URL del repositorio origen, las credenciales si es privado, y Forgejo lo importa incluyendo branches, tags, issues, y pull requests si el origen lo soporta.

Migrar desde Gitea es igual de simple. El formato interno es compatible, así que también puedes hacer backup y restore directamente.

Forgejo Actions: CI/CD propio
#

Esta es la parte que más ha cambiado mi flujo de trabajo. Antes tenía algunos scripts que corrían en cron para tareas de CI básicas. Con Forgejo Actions puedo tener pipelines declarativos, con logs bonitos, historial de ejecuciones, y notificaciones cuando algo falla.

La sintaxis es la misma que GitHub Actions. Si ya la conoces, no hay nada nuevo que aprender. Si no la conoces, es YAML con triggers y jobs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
name: Build y test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Configurar Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Instalar dependencias
        run: pip install -r requirements.txt
      
      - name: Ejecutar tests
        run: pytest

Este workflow se ejecuta en cada push a main y en cada pull request. Si los tests fallan, el PR queda bloqueado y recibes notificación.

Para que funcione, necesitas el runner de Forgejo Actions. Se instala como proceso separado:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
version: "3"
services:
  forgejo-runner:
    image: code.forgejo.org/forgejo/runner:3
    container_name: forgejo-runner
    volumes:
      - ./forgejo-runner:/data
      - /var/run/docker.sock:/var/run/docker.sock
    command: >-
      /bin/sh -c
      "while : ; do
        forgejo-runner create-runner-file --connect --instance https://forgejo.tu-dominio.com --name runner-local --secret TOKEN_REGISTRO --labels docker:docker://node:20,ubuntu-latest:docker://ubuntu:22.04;
        forgejo-runner daemon;
        sleep 1;
      done"
    restart: unless-stopped

El TOKEN_REGISTRO lo obtienes en Forgejo en Site Administration > Runners. Creas un nuevo runner, te da un token, y lo pegas en la configuración del runner.

Lo que hace el runner es conectarse a tu instancia de Forgejo, registrarse, y esperar jobs. Cuando hay un workflow que ejecutar, Forgejo lo manda al runner que esté disponible, el runner lo ejecuta (por defecto en un contenedor Docker) y devuelve los logs y el resultado.

El volumen del socket de Docker le permite al runner lanzar contenedores Docker como parte de los jobs. Para la mayoría de los casos de uso de homelab es suficiente. Si necesitas runners más aislados o con hardware específico, puedes tener varios runners en diferentes máquinas.

Packages: tu propio registro Docker
#

Una de las funciones que más uso es el registro de packages de Forgejo. Puedes usarlo como registro Docker privado para las imágenes que construyes.

Para usarlo, le das a Docker las credenciales de tu servidor:

1
docker login forgejo.tu-dominio.com -u tu-usuario -p tu-contraseña

Luego puedes hacer push de imágenes:

1
2
docker build -t forgejo.tu-dominio.com/tu-usuario/mi-app:latest .
docker push forgejo.tu-dominio.com/tu-usuario/mi-app:latest

Y puedes usar esas imágenes en tus Docker Compose o en tus deployments de K3s directamente, sin depender de Docker Hub.

En los workflows de Forgejo Actions puedes automatizar el build y push de imágenes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Login al registro
        uses: docker/login-action@v3
        with:
          registry: forgejo.tu-dominio.com
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_PASSWORD }}
      
      - name: Build y push
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: forgejo.tu-dominio.com/tu-usuario/mi-app:latest

Los secrets de Forgejo funcionan igual que los de GitHub Secrets: los defines en el repositorio, quedan cifrados, y los workflows pueden usarlos sin que aparezcan en los logs.

También soporta registros npm, PyPI, y Helm Charts. Si desarrollas paquetes para uso interno, puedes alojarlos todos en Forgejo sin depender de registros públicos.

SSH y acceso
#

Para clonar repositorios con SSH, Forgejo usa el puerto que configuraste (en mi caso 2222 para no interferir con el SSH del servidor). Para evitar tener que especificar el puerto en cada operación git, añade esto al ~/.ssh/config del cliente:

1
2
3
4
5
Host forgejo.tu-dominio.com
  HostName forgejo.tu-dominio.com
  User git
  Port 2222
  IdentityFile ~/.ssh/id_ed25519

Con eso, git clone [email protected]:usuario/repo.git funciona sin más.

Para añadir tu clave SSH a Forgejo, en la configuración de tu perfil está “SSH and GPG Keys”. Pegas tu clave pública y ya puedes clonar y pushear con autenticación SSH.

Los access tokens también están disponibles para scripts y herramientas que necesiten acceder a la API. En la configuración del perfil, “Applications”, puedes crear tokens con permisos granulares. Úsalos en lugar de la contraseña en los scripts automatizados.

Webhooks e integraciones
#

Para integraciones con otras herramientas, Forgejo tiene webhooks. Cuando ocurre un evento (push, pull request, issue abierto, release creada), Forgejo puede hacer un POST a una URL con el payload del evento.

Casos de uso habituales:

Notificación por Ntfy cuando alguien hace push: webhook con POST a tu servidor Ntfy para que llegue al móvil.

Trigger de un deployment: webhook que llama a un endpoint de n8n o a un script en el servidor para que haga el deploy automáticamente cuando se mergea en main.

Integración con Gitea/GitHub como mirror: Forgejo puede hacer mirror bidireccional con GitHub. Si también quieres tener el código en GitHub para visibilidad pública, configuras el mirror y los dos se mantienen sincronizados.

La configuración del webhook va en el repositorio, Settings > Webhooks > Add Webhook. Eliges el tipo (Forgejo, Slack, Teams, Discord, o genérico), pones la URL, y seleccionas qué eventos te interesan.

La UI y la experiencia de uso
#

La interfaz de Forgejo es prácticamente idéntica a Gitea, que a su vez se parece mucho a GitHub. Si has usado GitHub, encontrarás el mismo tipo de navegación: barra superior con el logo y acceso rápido, sidebar con repos y organizaciones, la mayoría de las acciones en menús contextuales de dos niveles.

Hay diferencias visuales pequeñas y algunas opciones están en lugares ligeramente diferentes, pero no es un aprendizaje nuevo. En general la interfaz es limpia y no tiene la tendencia de GitHub de añadir elementos de marketing o sugerencias de pago en cada página.

El dark mode funciona bien. La carga de las páginas es rápida incluso en el servidor más humilde porque Forgejo no depende de JavaScript pesado para renderizar el contenido principal.

Una cosa que me gustó al migrar desde Gitea: el import/export de datos está más documentado en Forgejo y el formato es estable. Si en el futuro quiero migrar de nuevo o hacer backup de todo, es straightforward.

Federación (en desarrollo)
#

Forgejo está trabajando en implementar federación ActivityPub para repositorios. La idea es que dos instancias de Forgejo puedan interoperar: puedes abrir un issue en un repositorio de otra instancia sin tener cuenta ahí, o hacer star desde tu instancia a un repositorio de otra instancia.

Esto está en desarrollo y no está habilitado por defecto en la versión estable, pero es uno de los puntos de diferenciación más interesantes respecto a Gitea y al resto de alternativas. Un ecosistema git federado, similar a cómo funciona el Fediverso para redes sociales.

Cuando esté maduro será útil para colaborar con otras personas que también tienen sus instancias de Forgejo sin necesitar que todos se creen cuenta en el mismo servidor.

Comparativa con Gitea
#

Si ya tienes Gitea, estas son las diferencias prácticas hoy:

Forgejo tiene Forgejo Actions listo para producción. Gitea tiene Gitea Actions pero el desarrollo ha ido más lento. Si usas CI/CD, Forgejo va por delante.

Forgejo está bajo la Software Freedom Conservancy, lo que da garantías de que el proyecto no puede ser adquirido o tomado por una empresa sin consentimiento de la comunidad. Si eso te importa (a mí me importa), es un punto a favor.

La sintaxis y el API son compatibles. Los clientes git, las integraciones de VS Code o JetBrains, y los scripts que funcionen con Gitea funcionan con Forgejo sin cambios.

La migración desde Gitea es tan simple como hacer backup del directorio de datos y restaurarlo en Forgejo. Yo lo hice en menos de una hora, incluyendo reconfigurarlo detrás del reverse proxy.

Comparativa con GitLab CE
#

GitLab Community Edition es más completo: tiene CI/CD más maduro, gestión de proyectos más sofisticada, y más integraciones. También consume bastante más recursos. GitLab recomienda al menos 4 GB de RAM para una instalación básica y en la práctica prefiere más.

Forgejo corre sin problemas con 512 MB de RAM para uso personal. En un VPS pequeño o en un nodo del homelab con recursos limitados, Forgejo es mucho más adecuado que GitLab.

Si necesitas las funciones avanzadas de GitLab (DAST, gestión de vulnerabilidades, herramientas de planificación de sprints), GitLab CE es la opción. Para la mayoría de casos de homelab, Forgejo cubre el 90% con el 10% de los recursos.

Lo que más uso en el día a día
#

Repositorios privados para scripts del homelab. Poder versionar los Docker Compose, las configuraciones de Kubernetes, los scripts de backup, y tener historial de cambios es algo que debería haber hecho desde el principio. Cuando algo deja de funcionar, git log y git diff me dan el contexto que necesito.

Forgejo Actions para validar los scripts antes de usarlos en producción. Tengo workflows que ejecutan ShellCheck en los scripts de shell, que hacen lint de los archivos YAML, y que corren algunas pruebas básicas. Es mucho más fácil detectar errores antes de que lleguen al servidor.

El registro Docker para las imágenes personalizadas. Tengo algunas imágenes que construyo con configuraciones específicas. En lugar de Docker Hub, van a Forgejo. Más control, sin límites de tráfico.

Si tienes código que versionar en el homelab y aún no tienes una solución propia, Forgejo es el punto de partida más directo. La instalación tarda menos de una hora, el mantenimiento es mínimo, y no dependerás de GitHub ni de ningún otro servicio externo para alojar tu código.