Self-hosting Forgejo (lightweight software forge)

Forgejo

INFO

Este post corresponde a una primera toma de contacto que he hecho con Forgejo y la configuración que aquí detallo puede no ser la más adecuada para un entorno de producción

Forgejo se define como un sistema que puedes autoalojar donde "forjar" tus proyectos, es decir, no es sólo un gestor de repositorios Git sino que cuenta con herramientas similares a otros servicios como Gitlab o GitHub, permitiendo el ejecutar pipelines antes un commit en un repo, gestión de proyectos, etc. todo ello alojado en tus sistemas y administrado por tí mismo.

Objetivo

Tras leer la documentación (bastante completa pero algo desordenada) he "conseguido" montar en un VPS, una máquina en un proveedor de Internet, mi instancia https://git.jagedn.dev

El objetivo es más bien poder evaluar el producto por si le puede interesar en algún momento a un cliente que el tener alojados mis repositorios personales cosa que tampoco descarto.

Requisitos

  • Como en mi caso quiero acceder desde internet (al estilo de GitHub) he añadido en mi dominio una entrada en el DNS, git.jagedn.dev apuntando a esta máquina

  • Una máquina donde instalar el stack. He usado Debian última versión. Acceso ssh a la misma

Forgejo en sí no pide mucha máquina. Empecé con un VPS de 3 euros al mes con 1Gb de memoria y funcionaba perfectamente, pero al ir añadiendo más cosas lo he subido a 2Gb por 5 euros al mes. Entiendo que esto es suficiente para proyectos personales pero para entornos con más usuarios y repositorios lo mínimo sean 8Gb

  • Docker instalado

Arquitectura

Diagram

Como se puede ver en el diagrama la solución se compone de dos partes principales:

  • Usuario usando Forgejo con Caddy en medio haciendo de proxy y resolviendo el certificado https

  • Runner dialogando con Forgejo para la ejecución de jobs

En mi caso todo reside en la misma máquina, aunque separado en carpetas y procesos diferentes, pero la idea es poder ejecutar los runners en máquinas separadas y poder añadir tantos como se quiera (o se disponga)

Forgejo

En una carpeta forgejo/server he creado la subcarpeta forgejo-data y a esta le he asignado el usuario 1000:1000 (para que coincida con el usuario que usa la imagen docker)

Así mismo he creado un fichero simple para configurar Caddy:

Caddyfile
git.jagedn.dev {
    reverse_proxy forgejo:3000
}

Como voy a ser el único usuario del sistema no voy a complicarme y el stack usará un base de datos SQLite, pero en otros casos más complejos seguramente habría que usar PostgreSQL o algún otro soportado por Forgejo

Mi docker-compose es tan simple como:

/stack/forgejo/server/docker-compose.yml
version: '3.8'

services:
  caddy:
    image: caddy:2-alpine
    container_name: caddy
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy-data:/data
      - ./caddy-config:/config

  server:
    image: codeberg.org/forgejo/forgejo:16.0.3
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    volumes:
      - ./forgejo-data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "2222:22"   # SSH para git clone/push

Caddy será quien exponga los puertos Web y Forgejo abrirá un puerto ssh en el 2222 (sujeto a posibles cambios)

Si hacemos un docker compose up -d podremos acceder al interface de Forgejo para configurarlo.

OJO en este momento tu instancia está abierta al mundo mundial, así que configura la password de admin inmediatamente. He leído que la password se puede configurar por variable de entorno, pero no lo he investigado a fondo.

Repositorio

El interface de Forgejo es muy similar a Codeberg, Github o Gitlab, ofreciendo similares funcionalidades.

Lo primero que habría que hacer, al igual que con estos otros servicios, es subir una clave SSH de nuestro sistema para facilitarnos el uso de git desde nuestra máquina.

Básicamente, es ir a la configuración de nuestra cuenta y en claves SSH subir alguna clave pública que tengamos en ~/.ssh/. Una vez subida podremos indicarle a git que use la clave privada para "dialogar" con nuestra instancia de forgejo.

Crear un repo es bastante sencillo y prácticamente igual que con los otros servicios. Para clonar el repo recién creado tendremos que decirle a git qué clave usar, por ejemplo:

$ git -c core.sshCommand="ssh -i ~/.ssh/id_ed25519" clone ssh://git@git.jagedn.dev:2222/jorge/test.git

Una vez clonado el repo puedo configurarlo para que use esa clave y no tener que especificarla cuando quiero subir cambios:

jorge/test>$ git config core.sshCommand "ssh -i ~/.ssh/id_ed25519"

Actions

Al estilo de GitHub Actions, podemos añadir una carpeta .forgejo/workflows (ojo al punto inicial) donde definir los pipelines del proyecto.

.forgejo/workflows/build.yaml
on: [push]
jobs:
  test:
    runs-on: "ubuntu-latest"
    steps:
      - run: echo All good!

Sin embargo, para que esta action se ejecute debemos crear y configurar un Runner.

Runner

Podemos crear tantos runner como queramos/podamos. Para cada uno de ellos primero tendremos que crearle un token desde el interface admin/actions/runners (o nodos si el interface está en español)

Una vez que tenemos el UID y el token creados por Forgejo vamos a desplegar un Runner usando Docker (No necesitas usarlo pero yo soy fan de Docker)

El siguiente docker compose es una copia casi exacta del de la documentación. Como dicen en la misma es más un ejemplo y no es para producción, pero para poder evaluar el sistema me sirve por ahora

Mi fichero docker-compose.yml es idéntico a este salvo con la configuración ajustada a mi instancia, cambiando la última línea del register:

sed -i -e "s| connections:| connections:\n default:\n url: https://git.jagedn.dev\n uuid: xxxxx-xxxx-xxxx-yyyy-zzzzzzz\n token: 02zxxxxxxxxxx|" config.yml;

WARNING

Esta NO es la forma de desplegar en producción pero me sirve para evaluar el sistema de una forma fácil.

Una vez levantado el docker podremos ver el Runner "online" en la consola de Forgejo

Labels

Los runners deben ser etiquetados para que Forgejo sepa a cúal enviarle un trabajo.

En el docker-compose de ejemplo anterior podemos ver que por defecto se han creado las labels

`[\"docker-cli:docker://code.forgejo.org/oci/docker:cli\", \"node:docker://code.forgejo.org/oci/node:lts\"]|"

Es decir, si un action indica que se debe ejecutar en docker-cli Forgejo buscará un Runner con esta etiqueta y a su vez el Runner sabrá que tiene que usar la imagen code.forgejo.org/oci/docker:cli para ejecutarlo.

De la misma forma si el job indica que se debe ejecutar en node el runner sabe que tiene que usar la imagen code.forgejo.org/oci/node:lts

Antes de levantar el docker yo he añadido un par de etiquetas más a la lista:

\"debian:docker://docker.io/library/node:lts\", \"ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04\"

Ejemplo Gradle

Una vez configurado y levantado el runner he creado un ejemplo más complejo que un simple "hello world" y he creado una aplicación Micronaut con Gradle (momento en el que tuve que redimensionar mi instancia y pasarle a 2Gb)

En este proyecto en creado un action simple para probar que se construye sin problemas:

mn-test/.forgejo/workflows/build-and-push.yaml
name: Build and Push Docker Image

on:
  push:
    branches:
      - main
jobs:
  build-and-push:
    runs-on: ubuntu-latest

    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up JDK 25
        uses: actions/setup-java@v4
        with:
          java-version: '25'
          distribution: 'temurin'
          cache: 'gradle'

      - name: Make gradlew executable
        run: chmod +x ./gradlew

      - name: Log in to Forgejo Container Registry
        uses: docker/login-action@v3
        with:
          registry: git.jagedn.dev
          username: ${{ github.actor }}
          password: ${{ secrets.PERSONAL_TOKEN }}

      - name: Build with Gradle
        run: ./gradlew build dockerfile -x test

Cada vez que subo cambios a main puedo ver cómo el runner ejecuta el pipeline (usando DockerInDocker para más seguridad) y consultar los logs

Publicando imágenes Docker

Una vez que he visto que los runner se ejecutan (según la capacidad de cada uno) he pasado a probar si podrían construir una imagen Docker del aplicativo y subirlo a Forgejo, al estilo de Gitlab o GitHub.

Micronaut añade la tarea dockerfile para facilitar el construir estas imágenes así que lo que faltaría sería añadir en el pipeline un docker build y un docker push (a grandes rasgos)

Esto se consigue (existirán otras formas seguramente) añadiendo unos pocos steps más al pipeline:

mn-test/.forgejo/workflows/build-and-push.yaml
name: Build and Push Docker Image
   ...
      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: git.jagedn.dev/${{ github.repository }}
          tags: |
            type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }}
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=sha,format=short

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: build/docker/main
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Una vez subidos los cambios en el pipeline, y si todo va bien, se puede ver la imagen tageada en la pestaña packages del repositorio.

Si el repo es público cualquiera podría ejecutar la imagen, por ejemplo:

docker run --rm -p 8080:8080 git.jagedn.dev/jorge/mn-test:sha-8a6a699

Conclusion

Aunque la arquitectura que he implementado es la que quiero (separar Forgejo de los Runner por ejemplo), la forma de configurar y desplegar no es del todo la deseable por lo que seguiré leyendo más a fondo la documentación

Tras probarlo un poco con un par de proyectos y en una instancia sin muchos recursos, me parece un producto muy bueno y completo

Este texto ha sido escrito por un humano

This post has been written by a human

2019 - 2026 | Mixed with Bootstrap | Baked with JBake v2.6.7 | Terminos Terminos y Privacidad