Forgejo Docker Compose: Tu Servidor Git Self-Hosted 2026

Forgejo Docker Compose ejecutando un servidor Git self-hosted

Con Forgejo Docker Compose levantas tu propio servidor Git completo en menos de diez minutos: repositorios privados sin límite, revisiones de código, registro de paquetes y CI/CD integrado. Todo en tu hardware, sin cuotas por colaborador y sin que nadie analice tu código para entrenar modelos.

Consume unos 200 MB de RAM en reposo. Un mini PC reciclado o una Raspberry Pi 4 le sobran para dar servicio a un equipo pequeño.

Qué es Forgejo y por qué no es simplemente Gitea

Forgejo es una forja de software libre: un servidor Git con interfaz web, incidencias, revisiones de código, wiki, registro de paquetes y CI/CD. La pregunta obvia si conoces el ecosistema es en qué se diferencia de Gitea, y la respuesta tiene más de gobernanza que de tecnología.

El proyecto nació en octubre de 2022, cuando los dominios y la marca de Gitea pasaron a una empresa con ánimo de lucro. Codeberg, que era uno de los grandes usuarios de Gitea, impulsó la bifurcación. Empezó como fork blando, se convirtió en hard fork en marzo de 2024 y en agosto de ese año cambió su licencia a GPLv3+, una licencia copyleft. Hoy la marca y los dominios están en manos de Codeberg e.V., una asociación sin ánimo de lucro.

En la práctica, si vienes de nuestro tutorial de Gitea con Docker Compose te encontrarás en casa: la interfaz y los conceptos son reconocibles. Las diferencias se acumulan release a release, y el propio proyecto mantiene una comparación honesta con Gitea que merece la pena leer antes de decidir.

Qué incluye de serie

Conviene saber qué entra en la caja antes de montarlo, porque cubre bastante más terreno del que la gente espera de un servidor Git:

  • Repositorios ilimitados, públicos y privados, sin coste por colaborador.
  • Incidencias, hitos y tableros de proyecto para llevar el seguimiento del trabajo.
  • Pull requests con revisión de código, comentarios en línea y reglas de protección de ramas.
  • Registro de paquetes multiformato: OCI, npm, PyPI, Maven, NuGet, Cargo y más.
  • CI/CD integrado con sintaxis compatible con la de GitHub Actions.
  • Wiki, releases y federación mediante ActivityPub, todavía en desarrollo.

Esa combinación es la que justifica el esfuerzo: no sustituyes solo a GitHub, también al registro de contenedores y al servidor de CI que quizá tengas por separado.


Requisitos previos para Forgejo Docker Compose

RecursoMínimoRecomendado
RAM512 MB2 GB
CPU1 núcleo2 núcleos
Disco10 GB50 GB o más
Docker Engine24.xÚltima estable

Forgejo Docker Compose es exigente sobre todo con el disco, así que sé generoso: los repositorios crecen, pero lo que dispara el consumo de verdad son el registro de paquetes y los artefactos de CI. Con 10 GB haces pruebas; para uso real, empieza en 50 GB.

Configuración de Forgejo Docker Compose paso a paso

Vamos directamente a la configuración de Forgejo Docker Compose con PostgreSQL. Se puede usar SQLite y funciona, pero en cuanto tengas varios repositorios activos y CI en marcha, notarás bloqueos de escritura. Migrar después es un engorro; empezar bien no cuesta nada. Usaremos la imagen oficial de PostgreSQL en su variante Alpine, más ligera.

Crea el directorio de trabajo y el fichero de variables. Nunca dejes las credenciales dentro del compose.

mkdir -p ~/forgejo && cd ~/forgejo
mkdir -p ./data ./postgres

cat > .env <<'EOF'
POSTGRES_USER=forgejo
POSTGRES_PASSWORD=cambia-esta-clave-larga-y-aleatoria
POSTGRES_DB=forgejo
FORGEJO_DOMAIN=git.midominio.es
EOF

chmod 600 .env

Ahora el docker-compose.yml. Está basado en el ejemplo oficial, con las variables extraídas al fichero .env y algunos ajustes de red y de dominio.

networks:
  forgejo:
    external: false

services:
  server:
    image: codeberg.org/forgejo/forgejo:16
    container_name: forgejo
    restart: always
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - FORGEJO__database__DB_TYPE=postgres
      - FORGEJO__database__HOST=db:5432
      - FORGEJO__database__NAME=${POSTGRES_DB}
      - FORGEJO__database__USER=${POSTGRES_USER}
      - FORGEJO__database__PASSWD=${POSTGRES_PASSWORD}
      - FORGEJO__server__DOMAIN=${FORGEJO_DOMAIN}
      - FORGEJO__server__ROOT_URL=https://${FORGEJO_DOMAIN}/
      - FORGEJO__server__SSH_DOMAIN=${FORGEJO_DOMAIN}
      - FORGEJO__server__SSH_PORT=222
      - FORGEJO__service__DISABLE_REGISTRATION=true
    networks:
      - forgejo
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    container_name: forgejo-db
    restart: always
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    networks:
      - forgejo
    volumes:
      - ./postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

Levanta la pila de Forgejo Docker Compose y comprueba que ambos contenedores quedan en estado saludable. Si la base de datos tarda en arrancar la primera vez, es normal: está inicializando el clúster.

docker compose up -d
docker compose ps
docker compose logs -f server

Entra en http://IP-DEL-SERVIDOR:3000 y verás el asistente de instalación. Los datos de base de datos vienen ya rellenos desde las variables de entorno; lo importante aquí es crear la cuenta de administrador antes de exponer nada al exterior.

Variables de entorno que conviene conocer

VariablePara qué sirve
USER_UID / USER_GIDAlinean el usuario del contenedor con el del host y evitan problemas de permisos en ./data.
FORGEJO__server__ROOT_URLURL pública. Si está mal, los enlaces de clonado y los correos saldrán rotos.
FORGEJO__server__SSH_PORTPuerto anunciado en la interfaz, no el interno. Debe coincidir con el publicado.
FORGEJO__service__DISABLE_REGISTRATIONCierra el registro público. Imprescindible si el servidor es accesible desde Internet.

Cualquier opción del fichero app.ini se puede fijar con este patrón de doble guion bajo. El manual de configuración recoge el listado completo, que es enorme.

Dónde viven los datos

Este despliegue de Forgejo Docker Compose usa montajes de directorio en lugar de volúmenes con nombre, y es una decisión deliberada: los ficheros quedan a la vista, se respaldan con un tar normal y no dependes de docker volume para recuperarlos.

Ruta en el hostContenido
./data/git/repositoriesLos repositorios Git en bruto.
./data/gitea/conf/app.iniConfiguración efectiva del servidor.
./data/gitea/packagesRegistro de paquetes y contenedores.
./data/gitea/actions_artifactsArtefactos generados por el CI.
./postgresDatos de PostgreSQL.

Sí, varias rutas internas conservan el nombre gitea: es herencia del origen común y no supone ningún problema. Anota estas ubicaciones porque son exactamente las que necesitarás cuando toque restaurar.


Publicar Forgejo Docker Compose con HTTPS

Servir esto en claro por el puerto 3000 no es una opción si va a salir de tu red local. Lo habitual es ponerle delante un proxy inverso que gestione los certificados. Si ya tienes montado Traefik como proxy inverso con SSL automático, basta con añadir etiquetas al servicio.

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.forgejo.rule=Host(`git.midominio.es`)"
      - "traefik.http.routers.forgejo.entrypoints=websecure"
      - "traefik.http.routers.forgejo.tls.certresolver=letsencrypt"
      - "traefik.http.services.forgejo.loadbalancer.server.port=3000"

Advertencia: el SSH no pasa por el proxy

Un proxy HTTP no enruta Git por SSH. El puerto 222 tiene que llegar directamente al contenedor, así que ábrelo en el cortafuegos de forma explícita y restringido a los orígenes que necesites. Si prefieres no exponerlo, trabaja solo con HTTPS y tokens de acceso personal.

Comprueba que el acceso por SSH funciona antes de dar por buena la instalación. La respuesta correcta es un saludo del servidor seguido del cierre de la conexión.

ssh -T -p 222 git@git.midominio.es

Registro de paquetes y CI con Forgejo Docker Compose

Aquí es donde Forgejo Docker Compose deja de ser «solo Git». El registro de paquetes viene activado de serie y admite contenedores OCI, npm, PyPI, Maven, NuGet y bastantes más, sin configuración adicional.

docker login git.midominio.es
docker tag mi-app:1.0 git.midominio.es/miusuario/mi-app:1.0
docker push git.midominio.es/miusuario/mi-app:1.0

La parte de CI se llama Forgejo Actions y usa una sintaxis muy parecida a la de GitHub Actions, con los ficheros en .forgejo/workflows/. Necesita un componente aparte, el runner, que es quien ejecuta los trabajos en contenedores.

  runner:
    image: code.forgejo.org/forgejo/runner:6
    container_name: forgejo-runner
    restart: always
    depends_on:
      - server
    networks:
      - forgejo
    volumes:
      - ./runner:/data
      - /var/run/docker.sock:/var/run/docker.sock
    command: forgejo-runner daemon

Antes de arrancarlo hay que registrarlo con el token que genera la interfaz de administración. Ten presente que montar el socket de Docker da al runner control efectivo sobre el host: hazlo solo si confías en quien puede escribir workflows en tus repositorios.


Endurecer Forgejo Docker Compose antes de exponerlo

Un servidor Git accesible desde Internet acumula intentos de registro automatizado en cuestión de horas. Estas cuatro medidas son el mínimo razonable y se aplican en diez minutos.

  • Registro cerrado. Ya lo llevas puesto con DISABLE_REGISTRATION=true. Crea tú las cuentas o habilita el registro solo por invitación.
  • Doble factor obligatorio. En la administración puedes exigir 2FA a todas las cuentas; con acceso de escritura al código, no es opcional.
  • Repositorios privados por defecto. Evita el clásico despiste de publicar un repositorio con credenciales dentro.
  • Correo saliente configurado. Sin SMTP no hay recuperación de contraseña ni avisos de seguridad.

Si además quieres centralizar la identidad, Forgejo Docker Compose admite OAuth2 y OIDC contra un proveedor propio, de modo que puedes delegar el inicio de sesión en el mismo sistema que uses para el resto de servicios del homelab.


Copias de seguridad de Forgejo Docker Compose

Un servidor Git propio sin copias es una bomba de relojería. En Forgejo Docker Compose hay dos piezas que respaldar: el volumen de datos y la base de datos. Y tienen que ser consistentes entre sí.

#!/bin/bash
set -euo pipefail
DESTINO=/mnt/backups/forgejo/$(date +%F)
mkdir -p "$DESTINO"

docker compose exec -T db pg_dump -U forgejo forgejo \
  | gzip > "$DESTINO/forgejo-db.sql.gz"

tar czf "$DESTINO/forgejo-data.tar.gz" ./data

find /mnt/backups/forgejo -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +

Progámalo en cron y, sobre todo, prueba una restauración completa en otra máquina al menos una vez. Una copia que nunca has restaurado no es una copia, es una intención. Si prefieres algo con interfaz y cifrado, Duplicati para backups cifrados automáticos encaja bien apuntando a ese mismo directorio. Y para la base de datos conviene revisar las buenas prácticas de respaldo de PostgreSQL.

Mantenimiento y problemas frecuentes

Actualizar Forgejo Docker Compose es cambiar la etiqueta de la imagen y volver a levantar, pero con una precaución importante: haz siempre copia antes, porque las migraciones de base de datos no se revierten. Puedes automatizar las actualizaciones menores con Watchtower, aunque en un servidor Git yo prefiero hacerlas a mano.

SíntomaCausa habitualSolución
Permission denied en ./dataUID del host distintoAjustar USER_UID y chown -R 1000:1000 ./data
Enlaces de clonado con la IPROOT_URL mal fijadaCorregir dominio y reiniciar el contenedor
SSH pide contraseñaClave pública no cargadaAñadirla en el perfil de usuario
El runner no apareceRegistro sin completarVolver a registrar con un token nuevo
Disco lleno de golpeArtefactos de CI antiguosActivar la caducidad de artefactos

Conclusión sobre Forgejo Docker Compose

Migrar de una forja alojada a un Forgejo Docker Compose propio asusta menos de lo que parece, sobre todo porque Forgejo importa repositorios desde GitHub o GitLab con incidencias y pull requests incluidas. Lo que realmente decide el éxito no es la instalación, que es lo fácil, sino haber probado la restauración de la copia antes de necesitarla.

Si vienes de Gitea y estás cómodo, no hay urgencia por cambiar. Si empiezas de cero, la gobernanza sin ánimo de lucro y la licencia copyleft son argumentos sólidos para elegir este camino. Tienes el código en el repositorio oficial en Codeberg, la guía de despliegue en la documentación de instalación con Docker y más ideas para tu servidor en los tutoriales de Docker Compose del blog.

Preguntas frecuentes sobre Forgejo Docker Compose

¿Puedo migrar desde Gitea sin perder nada?

En versiones recientes ya no es un cambio de imagen directo, porque el hard fork separó los esquemas. La vía recomendada es exportar los repositorios y usar la herramienta de migración de la interfaz, que trae incidencias, etiquetas y pull requests.

¿Vale una Raspberry Pi?

Sí, hay imágenes para arm64 y una Pi 4 con 4 GB mueve sin problema un equipo pequeño. Usa SSD por USB en lugar de tarjeta microSD: los repositorios y la base de datos castigan mucho el almacenamiento.

¿Merece la pena la variante rootless?

Para exposición a Internet, sí. Cambia la ruta de datos a /var/lib/gitea, el puerto SSH interno a 2222 y exige fijar user: 1000:1000. Es algo más de trabajo inicial a cambio de reducir bastante la superficie de ataque.

¿Puedo usar SQLite en lugar de PostgreSQL?

Funciona para uso personal con pocos repositorios. En cuanto entran varios usuarios concurrentes o CI activo, aparecen bloqueos de escritura. Como la migración posterior es incómoda, compensa empezar directamente con PostgreSQL.

¿Cuánto ocupa realmente con el tiempo?

Los repositorios de código crecen despacio. Lo que dispara el disco son las imágenes del registro de contenedores y los artefactos de CI, así que configura políticas de caducidad desde el primer día y vigila el crecimiento el primer mes.

Avatar

Por Mid

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x
()
x