Servidor Git autohospedado: Forgejo, Gitea o cgit
Compara cuatro formas de alojar Git según su consumo de RAM: SSH, cgit, Forgejo o Gitea y GitLab. Descubre qué puede ejecutar un VPS de 1 GB.
Qué servidor Git autohospedado debería ejecutar
Un servidor Git autohospedado no es un único producto. La RAM (memoria de acceso aleatorio) de su VPS determina qué versión puede ejecutar. Git no necesita su propio daemon: un repositorio bare y una cuenta SSH (Secure Shell) ya forman un servidor funcional en el VPS más pequeño que puede alquilar. Todo lo que supera ese nivel es una aplicación web que elige ejecutar junto a él. Cada nivel adicional consume memoria que un VPS pequeño puede no tener.
Hay cuatro niveles. Un repositorio bare mediante SSH, sin ningún proceso escuchando que no lo hiciera ya. cgit, una vista web rápida y de solo lectura que no necesita una base de datos. Forgejo o Gitea, una forge completa con cuentas, incidencias y pull requests en unos pocos cientos de megabytes. GitLab, que requiere un servidor varias veces más grande que los demás.
Decida según el trabajo que necesita realizar. Después, compare la cantidad de memoria con el plan que está pagando.
Cuánta RAM necesita realmente cada opción
Sólo dos de estos proyectos publican una cifra de hardware. Considere esa cifra como un mínimo, no como una garantía, y mida su propia instancia cuando esté en ejecución con systemd-cgtop o ps -o rss= -C forgejo.
The data behind this chart
[
{
"label": "Gitea, small team",
"ram_gb": 1
},
{
"label": "GitLab, memory constrained",
"ram_gb": 8
},
{
"label": "GitLab, single node baseline",
"ram_gb": 16
}
]Gitea documenta 1 GB de RAM con 2 núcleos de CPU como una cantidad normalmente suficiente para equipos y proyectos pequeños, y señala que una Raspberry Pi 3 basta para cargas de trabajo pequeñas. GitLab documenta 16 GB como referencia mínima para una instalación de un solo nodo, y 8 GB como el límite inferior de lo que su propia página denomina un entorno con memoria limitada. Forgejo no publica ningún requisito de hardware. Es un fork de Gitea y se comporta de forma similar, por lo que la cifra de Gitea es la guía publicada más aproximada disponible.
Esto es lo que significa en un VPS de 1 GB: los repositorios desnudos y cgit funcionan con margen suficiente, porque ninguno ejecuta un servicio residente. Forgejo o Gitea arrancarán y podrán atender a un equipo pequeño con SQLite, pero estará en el mínimo documentado, así que deje PostgreSQL y el runner de CI (integración continua) fuera de ese equipo. Si la interfaz web desaparece sin mostrar un error, ejecute sudo dmesg -T | grep -i oom y busque una línea como Out of memory: Killed process 1181 (forgejo). Esto significa que el killer de falta de memoria del kernel lo terminó. GitLab en un equipo de 1 GB no es un problema de ajuste. No funcionará.
Nivel 0: un repositorio simple mediante SSH
Git no tiene ningún demonio de red que deba iniciar. git push mediante SSH ejecuta git-receive-pack en el extremo remoto como un proceso Unix normal, por lo que cualquier cuenta a la que pueda acceder con una clave ya es un remoto de Git. Cree una cuenta para los repositorios y manténgalos fuera de su directorio personal, porque en Ubuntu 24.04 un directorio personal nuevo tiene el modo 0750 y una interfaz web que se añada después no podrá acceder a él.
sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' \
--group --disabled-password --home /home/git git
sudo install -d -m 0755 -o git -g git /srv/git
sudo -u git git init --bare /srv/git/project.git--bare crea un repositorio sin copia de trabajo, que es lo que mantiene un servidor. El envío a un repositorio que sí tiene una copia de trabajo se rechaza con refusing to update checked out branch: refs/heads/main, y este es el error más común en este nivel.
Ahora asigne una clave a la cuenta y clone el repositorio.
sudo -u git install -d -m 700 /home/git/.ssh
sudo -u git tee -a /home/git/.ssh/authorized_keys <<'EOF'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIexamplekeyhere alice@laptop
EOF
sudo -u git chmod 600 /home/git/.ssh/authorized_keysgit remote add origin git@vps.example.com:/srv/git/project.git
git push -u origin mainUn primer envío correcto termina con * [new branch] main -> main. Si termina con git@vps.example.com: Permission denied (publickey), la autenticación nunca se completó; revise el registro del servidor con sudo journalctl -u ssh -n 20. Una línea que indique Authentication refused: bad ownership or modes for file /home/git/.ssh/authorized_keys significa que el modo del archivo es incorrecto, porque sshd ignora un archivo de claves en el que otros usuarios pueden escribir.
Después, quite el shell de la cuenta.
command -v git-shell | sudo tee -a /etc/shells
sudo chsh -s "$(command -v git-shell)" gitgit-shell acepta sólo los pocos comandos que Git envía mediante SSH, por lo que un inicio de sesión interactivo se detiene con un mensaje en lugar de mostrar un indicador:
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.Ese es todo el servidor. No hay ninguna base de datos ni ningún proceso web que actualizar. Lo que se pierde es todo lo que ofrece una forja: no hay exploración de repositorios, gestor de incidencias, solicitudes de incorporación de cambios ni permisos por usuario. Cada clave de ese archivo puede leer y escribir en todos los repositorios que pertenezcan al usuario git.
Nivel 1: cgit ofrece una vista web sin base de datos
cgit es un programa CGI (interfaz de puerta de enlace común) escrito en C. El servidor web lo ejecuta una vez por petición, lee los repositorios directamente del disco y no almacena ningún estado propio. Ubuntu 24.04 lo incluye en el componente universe.
sudo apt update
sudo apt install -y cgit fcgiwrap nginx
sudo install -d -o www-data -g www-data /var/cache/cgitIndique el directorio de repositorios en /etc/cgitrc:
root-title=Git on example.com
css=/cgit.css
logo=/cgit.png
cache-size=1000
cache-root=/var/cache/cgit
snapshots=tar.gz zip
scan-path=/srv/gitscan-path recorre ese directorio y muestra todos los repositorios que encuentra, por lo que un repositorio bare nuevo aparece sin configuración adicional. cache-size es el número de páginas almacenadas en caché; la caché permanece desactivada mientras sea cero. Revise lo que el paquete ya haya escrito en /etc/cgitrc antes de añadir líneas, porque los paquetes de Debian y Ubuntu incluyen algunos valores predeterminados propios.
Cada entrada muestra la primera línea del archivo description del repositorio, por lo que un repositorio bare nuevo aparece como Unnamed repository; edit this file 'description' to name the repository. Corríjalo una vez por repositorio:
echo 'Project X, internal tooling' | sudo -u git tee /srv/git/project.git/descriptionEl archivo de sitio de nginx y cómo comprobarlo
server {
listen 80;
server_name git.example.com;
root /usr/share/cgit;
try_files $uri @cgit;
location @cgit {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi;
fastcgi_param PATH_INFO $uri;
fastcgi_param QUERY_STRING $args;
fastcgi_param HTTP_HOST $server_name;
fastcgi_pass unix:/run/fcgiwrap.socket;
}
}sudo systemctl enable --now fcgiwrap.socket
sudo nginx -t && sudo systemctl reload nginx
systemctl show fcgiwrap.socket -p Listenroot /usr/share/cgit sirve cgit.css y cgit.png como archivos estáticos, y try_files entrega todo lo demás al CGI en /usr/lib/cgit/cgit.cgi. Una página 502, con connect() to unix:/run/fcgiwrap.socket failed (2: No such file or directory) en /var/log/nginx/error.log, indica que la unidad del socket no está ejecutándose o que escucha en otra ruta. La línea systemctl show muestra la ruta que usa realmente.
Conviene conocer dos límites antes de basarse en él. cgit es de solo lectura y no tiene inicio de sesión, por lo que todo lo que esté bajo scan-path es público: mantenga los repositorios privados fuera de ese directorio o coloque autenticación HTTP básica delante de todo el sitio. Además, el CGI se ejecuta con el usuario del servidor web, por lo que ese usuario debe poder atravesar /srv/git y leer cada repositorio. Un directorio al que no pueda acceder aparece como un índice vacío en lugar de mostrar un error.
Nivel 2: Forgejo o Gitea para incidencias y solicitudes de incorporación
Forgejo y Gitea siguen el mismo enfoque: un único binario de Go que ofrece una forja web con usuarios, organizaciones, incidencias, solicitudes de incorporación, versiones, un registro de paquetes y un sistema de CI integrado. El binario y SQLite constituyen toda la instalación, por lo que funcionan en hardware en el que GitLab no se puede ejecutar. El archivo Compose siguiente es el de la documentación de Forgejo, con la etiqueta de imagen que indica a fecha de agosto de 2026.
networks:
forgejo:
external: false
services:
server:
image: codeberg.org/forgejo/forgejo:16
container_name: forgejo
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
networks:
- forgejo
volumes:
- ./forgejo:/data
- /etc/localtime:/etc/localtime:ro
ports:
- '3000:3000'
- '222:22'docker compose up -d
docker compose ps
curl -sI http://127.0.0.1:3000 | head -1La línea curl debe mostrar una línea de estado HTTP. Antes de terminar la configuración inicial, puede devolver una redirección a /install, lo que también indica que el servicio está activo. Si el contenedor termina, la causa habitual son los permisos de propietario: el directorio ./forgejo debe pertenecer al UID (identificador de usuario) indicado en USER_UID, o el proceso no podrá escribir en su propio directorio de datos. Docker Compose en un VPS explica detalladamente esa estructura de archivos y la regla de propiedad de los volúmenes.
Dos respuestas de la página de configuración determinan si funcionan las URL de clonación. El puerto SSH debe ser 222, porque el archivo Compose asigna el puerto 222 del host al puerto 22 del contenedor, y el dominio debe ser el nombre que las personas escribirán realmente. Si uno de los dos valores es incorrecto, todas las páginas de repositorios ofrecerán un comando de clonación que fallará para cualquiera que lo copie. Ambos valores aparecen después en la sección [server] de app.ini, como SSH_PORT, SSH_DOMAIN y ROOT_URL.
En una instancia pública, publique el puerto web sólo en la dirección de loopback ('127.0.0.1:3000:3000') y coloque nginx delante para gestionar TLS (seguridad de la capa de transporte). Gitea se instala de la misma forma desde la imagen gitea/gitea, o como un único binario con una unidad de systemd y un único app.ini. Su versión estable actual es la 1.27.1 a fecha de agosto de 2026.
Mantenga SQLite mientras sea posible. La instancia se reduce a un proceso y un archivo, y sobrevive a un reinicio sin ningún servicio adicional que supervisar. PostgreSQL compensa su coste cuando varias personas escriben al mismo tiempo, porque SQLite serializa las escrituras y las ejecuciones largas de CI escriben constantemente. Ambos proyectos permiten migrar después una instancia existente a PostgreSQL, por lo que no es una decisión irreversible.
Forgejo o Gitea: diferencias reales
El linaje es compartido. Gitea se bifurcó de Gogs en 2016. A finales de 2022, el control del dominio y la marca registrada de Gitea pasó a una empresa, Gitea Ltd, y varios mantenedores, junto con Codeberg, iniciaron Forgejo. Codeberg e.V., una asociación sin ánimo de lucro registrada en Alemania, publica Forgejo, que pasó de la licencia MIT a GPLv3 (GNU general public license version 3) en 2024. Gitea mantiene la licencia MIT y se desarrolla con respaldo comercial.
En el día a día, los conjuntos de funciones son similares. La ruta de migración entre ambos no lo es. Forgejo v10.0, publicado en enero de 2025, fue la última versión que podía usar directamente una base de datos de Gitea, y sólo desde Gitea v1.22 o anteriores. Gitea está en 1.27.1 a fecha de agosto de 2026, por lo que una instancia actual de Gitea no tiene un cambio en el mismo lugar compatible y admitido hacia Forgejo. Elija uno antes de cargarlo con datos y considere cualquier migración posterior como una exportación y una nueva importación.
Una regla breve para elegir. Si la gobernanza es importante para usted o quiere que el proyecto siga en manos de una organización sin ánimo de lucro, use Forgejo. Si quiere una base de instalaciones más amplia y una opción de soporte comercial, use Gitea. Ambos se mantienen de forma abierta y publican versiones con frecuencia: Forgejo publica una versión estable cada tres meses y una versión LTS (long term support) cada año. A fecha de agosto de 2026, la versión actual es v16.0.2 y la versión LTS es v15.0.6.
Nivel 3: cuánto consume GitLab antes de hacer nada
GitLab CE pertenece a otra categoría de software. Una instancia es un conjunto de servicios que cooperan entre sí: Puma para la aplicación web, Sidekiq para los trabajos en segundo plano, PostgreSQL, Redis, Gitaly para acceder a los repositorios y nginx delante de todos ellos. El paquete Omnibus los instala juntos. Esto simplifica la instalación, pero eleva mucho el consumo mínimo de memoria.
La página de requisitos de GitLab documenta 16 GB de RAM y 8 vCPU como referencia para una instalación de un solo nodo. También indica 8 GB como el mínimo en un entorno con memoria limitada. La misma página recomienda desactivar el swap, porque el intercambio bajo carga degrada mucho la instancia. Estas son las cifras publicadas en agosto de 2026. Han aumentado con los años, así que vuelva a consultar la página antes de dimensionar el servidor.
Con ese presupuesto obtiene funciones reales: un registro de contenedores, un registro de paquetes, permisos detallados, funciones de cumplimiento y auditoría, y CI probado a gran escala. Si nadie de su equipo puede indicar una función de esa lista que necesite este trimestre, está pagando por un VPS más grande a cambio de nada.
El modelo de acceso SSH: un usuario de git y muchas claves
Todos los niveles se autentican de la misma forma. Hay una cuenta de Unix llamada git, y todas las claves públicas se guardan en el archivo ~/.ssh/authorized_keys de esa cuenta. La clave se utiliza para la autenticación. La autorización depende de las opciones que escriba delante de la clave en la misma línea.
Una línea de clave sin opciones concede al titular todo lo que esa cuenta puede hacer. Un comando forzado limita el acceso a Git:
restrict,command="git-shell -c \"$SSH_ORIGINAL_COMMAND\"" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIexamplekeyhere alice@laptoprestrict, disponible desde OpenSSH 7.2, desactiva el reenvío de puertos, el reenvío del agente, X11 y la asignación de una PTY (pseudo terminal) con una sola opción. command= sustituye lo que solicitó el cliente por el valor que indique, y Git sigue funcionando porque envía su solicitud en $SSH_ORIGINAL_COMMAND.
Una forja escribe ese archivo por usted. Esa es la diferencia real entre el nivel 0 y el nivel 2. Forgejo y Gitea reescriben authorized_keys con una línea por cada clave registrada. Cada línea incluye un comando forzado que identifica la clave mediante su ID de la base de datos:
command="/usr/local/bin/forgejo --config=/etc/forgejo/app.ini serv key-3",no-port-forwarding,no-x11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIexamplekeyhere aliceEse comando forzado permite que una cuenta de Unix compartida tenga permisos por usuario: key-3 indica a la forja qué usuario se está conectando, y la forja comprueba los permisos de ese usuario en el repositorio antes de transferir cualquier objeto. No edite manualmente ese archivo en un equipo administrado por una forja. La forja lo reescribe desde la base de datos y su línea desaparecerá. Las claves de despliegue utilizan el mismo mecanismo: una clave de despliegue es una clave SSH normal registrada para un único repositorio, normalmente con permisos de sólo lectura. La comprobación se realiza en la forja y no en sshd.
Dos prácticas son más importantes que la mayor parte de la configuración anterior. Emita una clave por persona o por máquina, nunca una clave compartida. Revocar una clave compartida obliga a cambiarla para todos al mismo tiempo. Elimine las claves el mismo día que alguien abandone el equipo o la organización. Una clave antigua en ese archivo permite iniciar sesión permanentemente y nadie la está supervisando. Una buena gestión de claves SSH en un servidor explica los tipos de clave y las frases de contraseña, y todo se aplica aquí sin cambios. Si el equipo es nuevo, los primeros diez minutos en un VPS nuevo es lo que debe hacer antes de alojar repositorios en él.
¿Puedo ejecutar GitHub Actions en mi propio servidor Git?
Puede ejecutar flujos de trabajo escritos con la sintaxis de GitHub Actions. No puede ejecutar GitHub. Forgejo Actions está habilitado de forma predeterminada desde Forgejo v1.21 y lee los archivos de flujo de trabajo de .forgejo/workflows en cada repositorio. Gitea Actions funciona de la misma manera y lee .gitea/workflows. Ambos necesitan un segundo programa, el runner, que debe instalarse y registrarse en la instancia con un token de la configuración de administración. Muchas acciones publicadas se ejecutan sin cambios. Sin embargo, no ocurre lo mismo con las que llaman a la API de GitHub o esperan una infraestructura alojada por GitHub.
Debe prever dos consecuencias. El runner inicia un contenedor para cada tarea. Por tanto, necesita un motor de contenedores y una cantidad de memoria propia. Por eso no debe instalarse en el mismo servidor de 1 GB que la forja. Además, el runner ejecuta todo lo que indique un archivo de flujo de trabajo. La documentación de Forgejo lo expresa claramente: el runner ejecuta código de forma remota. Siempre que sea posible, asígnele un host propio. Como mínimo, use su propio usuario sin privilegios y un token de registro limitado a un solo repositorio.
Si sus repositorios permanecen en GitHub y sólo quiere ejecutar las tareas en hardware bajo su control, se trata de una configuración distinta, con pasos diferentes: un runner de GitHub Actions autohospedado se conecta a un repositorio de GitHub y no necesita nada de esto. Si todavía está evaluando el coste de abandonar GitHub, qué ofrece realmente GitHub separa el alojamiento de Git de la red que lo rodea.
Copias de seguridad: los repositorios sólo contienen la mitad del estado
Un repositorio bare es un directorio, por lo que copiarlo copia todo su contenido. Un clon espejo desde otra máquina es una copia de seguridad real y se actualiza en el mismo lugar:
git clone --mirror git@vps.example.com:/srv/git/project.git
cd project.git && git remote updateEsto obtiene todas las referencias y todos los objetos. No obtiene los hooks del servidor ni el archivo description, por lo que, si usa hooks, conserve también una copia a nivel de archivos del directorio.
Un forge almacena en su base de datos las incidencias, las solicitudes de incorporación, los usuarios, las claves y los permisos. Una copia aislada de los repositorios elimina toda esa información. Ambos proyectos incluyen un comando de volcado que escribe la base de datos, los repositorios, la configuración y los archivos adjuntos en un solo archivo:
sudo -u git forgejo dump -c /etc/forgejo/app.ini -f /var/backups/forgejo-dump.zipCon Docker, el mismo comando se ejecuta dentro del contenedor. La ruta de configuración depende de la imagen, así que compruébela antes de escribir el comando:
docker compose exec server ls /data/gitea/conf
docker compose exec -u git server forgejo dump -c /data/gitea/conf/app.iniEjecútelo con el usuario propietario de los datos y escriba el archivo en un directorio en el que ese usuario pueda escribir. Después, copie el archivo fuera del servidor, porque una copia de seguridad que sólo existe en la máquina respaldada no es una copia de seguridad. La restauración es el paso que se suele omitir: descomprima ahora un volcado en un equipo disponible, para aprender el procedimiento en un momento tranquilo y no durante una interrupción del servicio.
Elegir según el escenario
Una persona con un portátil y un VPS, sin necesidad de navegar por el código: repositorios desnudos mediante SSH. No se ejecuta ningún servicio adicional ni hay nada que actualizar.
Lo mismo, pero con la necesidad de leer el código en un navegador y compartir enlaces: añada cgit. Sigue sin haber base de datos ni procesos residentes.
Un equipo que revisa el código de los demás y realiza un seguimiento de incidencias: Forgejo o Gitea, con 2 GB de RAM o más. Traslade el ejecutor de CI a otro equipo cuando los trabajos empiecen a requerir recursos reales.
Una organización que necesita un registro de contenedores y trazabilidad de auditoría, con 16 GB disponibles para el servidor: GitLab. Con menos memoria, no lo ponga en marcha.
Pasar de uno de los tres primeros niveles al siguiente es barato, porque en todos ellos los repositorios son directorios Git normales en disco. Empiece por el nivel más bajo que cubra sus necesidades. Si está decidiendo qué otros servicios merecen espacio en el mismo servidor, la lista breve de servicios que merece la pena alojar por cuenta propia sitúa un servidor Git junto a los demás servicios que compiten por esa RAM.
FAQ
¿Puede un VPS de 1 GB ejecutar Forgejo o Gitea?
Sí, para un equipo pequeño, con SQLite y sin otros servicios exigentes en el servidor. La documentación de Gitea indica que 1 GB de RAM y 2 núcleos de CPU suelen ser suficientes para equipos y proyectos pequeños, y Forgejo es un fork de Gitea con requisitos similares. No añada PostgreSQL ni un runner de CI a esa máquina. Si el servicio desaparece sin errores en su propio registro, ejecute sudo dmesg -T | grep -i oom: una línea que indique el proceso terminado significa que el kernel lo detuvo mediante el mecanismo de falta de memoria; la solución es contratar un plan mayor, no ajustar un flag.
¿Cuál es la diferencia entre Forgejo y Gitea?
Comparten parte de la historia del código y la mayoría de las funciones. Gitea se bifurcó de Gogs en 2016, y Forgejo se bifurcó de Gitea a finales de 2022, después de que el control de la marca registrada Gitea pasara a una empresa. Forgejo lo publica Codeberg e.V., una organización sin ánimo de lucro de Alemania, bajo GPLv3; Gitea mantiene la licencia MIT y cuenta con respaldo comercial. La diferencia práctica es la ruta de migración. Forgejo v10.0, de enero de 2025, fue la última versión que podía importar directamente una base de datos de Gitea, y sólo desde Gitea v1.22 o anteriores. Por tanto, una instancia actual de Gitea no admite un cambio local compatible.
¿Puedo ejecutar flujos de trabajo de GitHub Actions en un servidor Git autogestionado?
Forgejo Actions y Gitea Actions ejecutan flujos de trabajo escritos con la sintaxis YAML de GitHub Actions. Los leen de .forgejo/workflows y .gitea/workflows. Debe instalar un programa runner independiente y registrarlo en su instancia. Muchas acciones publicadas funcionan sin cambios, pero cualquier acción que llame a la API de GitHub no funciona. El runner ejecuta código arbitrario de sus repositorios e inicia un contenedor por trabajo. Así que debe asignarle su propio host o, como mínimo, su propio usuario sin privilegios, y no ejecutarlo en un servidor de 1 GB que ya tenga el forge.
¿Cómo hago una copia de seguridad de un servidor Git autogestionado?
Para los repositorios bare, git clone --mirror desde otra máquina copia cada ref y objeto, y git remote update dentro de ese mirror lo actualiza. En Forgejo o Gitea, los repositorios sólo son una parte del estado, porque las incidencias, las solicitudes de incorporación de cambios, los usuarios y las claves se almacenan en la base de datos. Use el dump integrado, sudo -u git forgejo dump -c /etc/forgejo/app.ini, o el mismo comando dentro del contenedor si la instalación usa Docker. Copie el archivo fuera del servidor y restáurelo una vez en una máquina de reserva para comprobar que el procedimiento funciona.