Guía de despliegue

Alojar Gitea en su propio VPS en 2026

Desplegar en un VPS Cloud →

Tutorial

Alojar Gitea en su propio VPS en 2026

Autoalojamiento13 min de lectura12 pasos

Gitea es una forja Git autoalojada escrita en Go, reconocida por su ligereza y su rapidez. Desplegarla en su propio VPS le ofrece un GitHub privado sin suscripción por usuario ni límite de repositorios privados. En 2026, Gitea 1.25 es la versión actual y Forgejo v16 se ha impuesto como el fork comunitario de referencia — esta guía cubre la instalación de Gitea, la puesta en marcha de pipelines CI/CD con Gitea Actions, la comparativa con Forgejo, la administración diaria y la resolución de los errores más frecuentes.

Contenido· Por qué autoalojar Gitea en un VPS1/15
  1. 01Por qué autoalojar Gitea en un VPS
  2. 02Beneficios concretos de un Gitea autoalojado
  3. 03Requisitos de hardware y software
  4. 04Desplegar Gitea con Docker y SSL
  5. 05Gitea Actions: CI/CD autoalojado en su VPS
  6. 06Gitea o Forgejo en 2026: ¿cuál elegir?
  7. 07Migrar de Gitea a Forgejo
  8. 08Forgejo v16: las novedades clave (julio de 2026)
  9. 09Administración diaria: webhooks, repositorios y limpieza de huérfanos
  10. 10Resolución avanzada de problemas: SSH y clonado HTTPS
  11. 11Gitea 28.1.0: la comparación de PR falla con exit 128
  12. 12Gitea Actions: valores YAML multilínea corruptos desde v28
  13. 13Pasar a Gitea 1.27 sin perder los accesos SSH
  14. 14Para ir más lejos: Forgejo y CI/CD avanzado
  15. 15La documentación oficial

Por qué autoalojar Gitea en un VPS

Gitea consume apenas 200 a 300 MB de RAM en reposo, lo que la convierte en una de las forjas Git más eficientes para autoalojar. En un VPS, usted conserva el control total de su código fuente: ningún dato es analizado por un tercero, ninguna limitación arbitraria sobre el número de repositorios privados o de colaboradores, y ningún coste que crezca con su equipo. Para una agencia o un desarrollador independiente, un único VPS puede alojar el conjunto de los proyectos de clientes con permisos aislados por organización. Gitea integra de forma nativa un CI/CD compatible con los flujos de trabajo de GitHub Actions (Gitea Actions), un registro de paquetes y un editor web, lo que cubre la casi totalidad de un ciclo de desarrollo sin dependencia externa.

Beneficios concretos de un Gitea autoalojado

  • Huella de memoria mínima: funciona con holgura en un VPS de 2 GB de RAM incluso con varias decenas de usuarios.
  • Repositorios privados sin facturación por puesto ni límite impuesto, a diferencia de los planes SaaS.
  • Gitea Actions integrado para ejecutar sus pipelines CI/CD sin servicio externo.
  • Registro de paquetes (Docker, npm, Composer, Maven) alojado en la misma instancia.
  • Autenticación granular: LDAP, OAuth2, tokens de acceso personales y claves SSH por usuario.
  • Copia de seguridad trivial: todo cabe en un volumen de datos y una base de datos.

Requisitos de hardware y software

Gitea es muy frugal. Para un equipo pequeño (hasta 20 usuarios), un VPS con 2 vCPU y 2 GB de RAM basta de sobra; prevea 4 GB si activa Gitea Actions con runners locales que compilan código. Reserve al menos 20 a 40 GB de almacenamiento SSD según el tamaño de sus repositorios. En cuanto al software: Docker Engine y el plugin Docker Compose instalados, un nombre de dominio (o subdominio del tipo git.yourdomain.com) que apunte a la IP del VPS mediante un registro A, y el puerto 22 reservado al SSH del servidor — Gitea expondrá su propio SSH en otro puerto para evitar el conflicto.

Desplegar Gitea con Docker y SSL

  1. Preparar el VPS y Docker

    Conéctese por SSH, actualice el sistema y luego instale Docker y el plugin Compose. Cree un directorio dedicado: mkdir -p /opt/gitea && cd /opt/gitea. Cree también un volumen de datos que sobreviva a las actualizaciones del contenedor.

  2. Redactar el docker-compose.yml

    Defina dos servicios: gitea (imagen gitea/gitea:1.25) y una base postgres:16. Monte ./gitea:/data para la persistencia, fije USER_UID/USER_GID en 1000, y mapee el SSH de Gitea al puerto 2222 del host: "2222:22". Deje el puerto HTTP 3000 interno, será servido por el reverse proxy.

  3. Lanzar los contenedores

    Ejecute docker compose up -d y luego docker compose logs -f gitea para seguir la inicialización. Compruebe que la conexión a PostgreSQL funciona antes de continuar.

  4. Configurar el reverse proxy

    Con Caddy, basta una sola línea: git.yourdomain.com { reverse_proxy localhost:3000 }. Caddy obtiene y renueva automáticamente el certificado Let's Encrypt. Con Nginx, cree un bloque server que haga de proxy hacia http://127.0.0.1:3000 y utilice certbot --nginx para el SSL.

  5. Finalizar la instalación web

    Abra https://git.yourdomain.com, complete el asistente indicando la URL base HTTPS y el host de la base de datos (db:5432). Defina correctamente el ROOT_URL, de lo contrario los enlaces de clonado serán erróneos. Despliegue «Ajustes opcionales > Ajustes de la cuenta de administrador», cree allí su cuenta de administrador y valide.

  6. Asegurar el SSH de los repositorios

    Configure sus clientes para clonar mediante ssh://[email protected]:2222/..., o añada un bloque Host en ~/.ssh/config para ocultar el puerto. Desactive el registro público en la administración si la instancia es privada.

Gitea Actions: CI/CD autoalojado en su VPS

Gitea Actions es el motor CI/CD nativo de Gitea, compatible con la sintaxis de los flujos de trabajo de GitHub Actions. Permite ejecutar pipelines directamente en su infraestructura, sin dependencia de ningún servicio externo.

Para activarlo, añada a su app.ini:

[actions]
ENABLED = true

Registre después un runner act_runner en un contenedor separado en el mismo VPS. Limite su RAM mediante mem_limit para que una compilación exigente no ahogue a Gitea. Para pipelines pesados (compilación, pruebas de integración), dedique un segundo VPS al runner.

Un flujo de trabajo mínimo para un proyecto Node.js va en .gitea/workflows/ci.yml:

on: [push, 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

El runner ejecuta este flujo de trabajo en cada push. Puede combinar múltiples trabajos, usar matrices de versiones y compartir artefactos entre pasos — exactamente como GitHub Actions, pero en su propio servidor.

Limite la RAM del contenedor act_runner a 2 GB mediante mem_limit: 2g en su docker-compose.yml si su VPS dispone de 4 GB en total. Así, incluso una compilación que consuma todo lo que se le asigna deja 2 GB para Gitea — suficiente para seguir atendiendo los push y pull requests durante la compilación. Para compilaciones que producen artefactos voluminosos (imágenes Docker, binarios), añada un volumen separado montado en /home/runner/work para no llenar el volumen de datos principal de Gitea.

Gitea o Forgejo en 2026: ¿cuál elegir?

Desplace la tabla

CriterioGitea 1.25Forgejo v16
GobernanzaSociedad comercial (Gitea Ltd)Asociación sin ánimo de lucro (Codeberg e.V.)
LicenciaMITMIT — 100 % software libre, sin edición empresarial
Recomendado por Awesome-SelfhostedNo (retirado en 2022)Sí — recomendación por defecto desde 2024
Federación ActivityPubNo previstaEn despliegue progresivo desde Forgejo v7 (abril de 2024), GA en v16
Compatibilidad con la API de GiteaReferenciaCompatible: misma API, mismos webhooks, mismo formato de datos
Seguridad — auditorías públicasEscasasAuditorías de código publicadas por la comunidad Codeberg
Hoja de ruta comunitariaDirigida por Gitea LtdGobernanza abierta, RFC públicas, voto de los contribuidores
Migración desde GiteaN/ASin pérdida de datos: mismo esquema de base y mismo formato de volumen

Migrar de Gitea a Forgejo

  1. Hacer una copia de seguridad de la instancia Gitea

    Antes de cualquier operación, haga un dump completo: docker exec -u git gitea gitea admin dump -c /data/gitea/conf/app.ini. Recupere el archivo generado fuera del contenedor y compruebe que el volumen ./gitea está incluido en su snapshot del VPS.

  2. Comprobar la compatibilidad de versión

    Forgejo v16 admite la migración desde Gitea 1.20 y posteriores. Si su instancia funciona con una versión anterior, suba primero a Gitea 1.21 o 1.22 mediante docker compose pull && docker compose up -d, y luego compruebe la ausencia de errores en los logs antes de continuar.

  3. Sustituir la imagen Docker

    En su docker-compose.yml, sustituya image: gitea/gitea:latest por image: codeberg.org/forgejo/forgejo:latest. El volumen de datos (./gitea:/data) y la base PostgreSQL permanecen sin cambios — Forgejo lee el mismo esquema y el mismo app.ini.

  4. Reiniciar y dejar que migre

    Ejecute docker compose pull && docker compose up -d. Forgejo aplica automáticamente las migraciones de esquema necesarias al arrancar. Siga docker compose logs -f forgejo hasta el mensaje que indica que el servidor HTTP escucha en el puerto 3000.

  5. Regenerar las claves SSH

    Como en toda actualización que cambia el binario referenciado en authorized_keys, regenere las entradas: docker exec -u git forgejo forgejo admin regenerate keys. Compruebe después que un git clone por SSH funciona desde un puesto cliente.

  6. Probar y validar

    Abra la interfaz web, compruebe los repositorios, los webhooks y los runners de Forgejo Actions. Los runners act_runner registrados con Gitea son compatibles — vuelva a conectarlos al nuevo token de registro si la clave ha cambiado.

Forgejo v16: las novedades clave (julio de 2026)

Forgejo v16.0.0 introduce la federación ActivityPub en disponibilidad general para las issues y las pull requests: una issue abierta en una instancia Forgejo puede recibir comentarios de usuarios de otra instancia, sin cuenta compartida. La versión integra también un gestor de secretos de instancia (cifrado AES-256 en reposo), un nuevo motor de búsqueda de código basado en el índice Bleve v2 con soporte de expresiones regulares, y mejoras significativas del planificador de tareas en segundo plano. En el plano de la seguridad, los tokens de API se almacenan ahora hasheados en base de datos (bcrypt) y no en texto plano — una migración automática al arrancar convierte los tokens existentes.

Administración diaria: webhooks, repositorios y limpieza de huérfanos

Una vez Gitea en producción, vuelven regularmente algunas operaciones de mantenimiento.

Gestionar los webhooks. Gitea registra el historial de cada envío en «Configuración del repositorio → Webhooks → Entregas recientes». Un webhook fallido (timeout, error HTTP 5xx) puede reproducirse manualmente desde ese historial. Si sus runners están en la misma red privada que Gitea, añada sus rangos IP a ALLOWED_HOST_LIST en la sección [webhook] de app.ini — de lo contrario las llamadas hacia localhost se bloquean por defecto desde Gitea 1.20.

Purgar los repositorios huérfanos. Un repositorio eliminado mediante la interfaz deja sus datos Git (objects/) en disco hasta la próxima ejecución de las tareas en segundo plano. Fuerce un paso inmediato desde el admin: «Administración del sitio → Tareas en segundo plano → Ejecutar: Purgar repos eliminados». El espacio liberado solo es visible tras docker exec -u git gitea gitea admin storage --remove-unlisted.

Cuota de almacenamiento por organización. Para instancias multi-inquilino, fije una cuota de repositorios por organización en app.ini bajo [repository]: MAX_CREATION_LIMIT = 50. Esto impide que una cuenta cree cientos de repositorios sin supervisión y llene el volumen de datos.

Resolución avanzada de problemas: SSH y clonado HTTPS

Permission denied (publickey) tras una actualización. La ruta del binario referenciado en authorized_keys ha cambiado (comprobado en 1.27). El servicio Gitea responde con normalidad por HTTPS, lo que enmascara el problema. Corrija con: docker exec -u git gitea gitea admin regenerate keys. Compruebe que un git clone por SSH funciona antes de dar por terminada la actualización.

Timeout o error SSL al clonar por HTTPS. Tres causas comunes: el ROOT_URL en app.ini no coincide con el dominio HTTPS real (enlaces rotos + posible bucle de redirección), el reverse proxy no reenvía la cabecera X-Forwarded-Proto: https (Gitea genera entonces URLs en HTTP), o el certificado Let's Encrypt ha caducado (Caddy y certbot lo renuevan automáticamente, pero solo si el DNS sigue apuntando al VPS). Verifique ROOT_URL primero: es la causa más frecuente tras una migración de dominio.

Clonado SSH lento o que se bloquea. El upload-pack SSH usa el mismo proceso Git que las operaciones web. Si su act_runner está utilizando todos los núcleos de CPU disponibles durante una compilación, las operaciones Git pueden quedar a la espera. Añada cpus: '1.5' al runner en el compose para reservarle núcleos sin privarlo por completo.

Database migration failed: column already exists. La base recibió una migración parcial (parada durante la actualización). Restaure el dump realizado antes de la actualización, parta de un volumen limpio y vuelva a lanzar.

Gitea 28.1.0: la comparación de PR falla con exit 128

Tras actualizar a Gitea 28.1.0, la vista de comparación de pull requests falla silenciosamente en repositorios grandes (superiores a 1,4 GB) con el error exit 128 "unable to fetch head branch". La causa raíz es un archivo de bloqueo obsoleto (commit-graph.lock) dejado por un git fetch ejecutado sin el indicador --no-write-commit-graph — comportamiento introducido en esta versión (issue upstream #39795, reportada el 15 de octubre de 2026).

Diagnóstico. Compruebe la presencia del archivo de bloqueo en el repositorio afectado:

docker exec -u git gitea find /data/gitea/repositories -name 'commit-graph.lock'

Corrección inmediata. Elimine el archivo de bloqueo obsoleto:

docker exec -u git gitea find /data/gitea/repositories -name 'commit-graph.lock' -delete

La comparación de PR se restaura de inmediato sin necesidad de reiniciar el contenedor.

Recomendación. La corrección definitiva fue integrada en PR #39798 y se incluye en Gitea 28.1.1+. Planifique la actualización a 28.1.1 o superior cuanto antes; las instancias que gestionan repositorios de gran tamaño se ven afectadas sistemáticamente tras un fetch concurrente.

Gitea Actions: valores YAML multilínea corruptos desde v28

Desde Gitea v28, los escalares de bloque plegado YAML (>) utilizados en campos with: de pasos de flujo de trabajo son malinterpretados en ejecución: los valores multilínea se truncan o concatenan sin saltos de línea, produciendo errores silenciosos difíciles de diagnosticar (issue upstream #39775, reportada el 15 de octubre de 2026).

Síntoma típico. Un parámetro with: definido en varias líneas con >:

- uses: some-action@v1
  with:
    config: >
      línea uno
      línea dos
      línea tres

…es recibido por la acción como línea uno línea dos línea tres (los saltos de línea se pierden), en lugar del valor esperado con separación por líneas.

Soluciones alternativas. Dos enfoques equivalentes:

1. Reemplace > (plegado) por | (literal) — los saltos de línea se conservan tal cual:

  with:
    config: |
      línea uno
      línea dos
      línea tres

2. Utilice una cadena entre comillas con \n explícitos si el valor debe permanecer en una sola línea lógica.

Este comportamiento afecta a todos los flujos de trabajo que usan bloques > dentro de with: desde la migración a v28; los bloques | y los escalares en línea no se ven afectados. Se está evaluando una corrección oficial en el repositorio upstream.

Pasar a Gitea 1.27 sin perder los accesos SSH

La versión 1.27 modifica la ruta interna del binario gitea referenciado en authorized_keys. Durante la actualización, las entradas existentes apuntan a la ruta antigua: cualquier intento de clonado o de push por SSH falla en silencio con Permission denied (publickey), sin mensaje de error del lado del servidor que apunte a la actualización. Después de cada actualización a la 1.27 (o a cualquier versión que cambie esa ruta), ejecute dentro del contenedor: docker exec -u git gitea gitea admin regenerate keys. El comando reescribe todas las entradas authorized_keys con la ruta correcta del binario. Compruebe después que un git clone por SSH funciona antes de dar por terminada la actualización.

JWT_SECRET_URI y JWT_SECRET no deben coexistir en app.ini. Si ambas claves están presentes, Gitea o Forgejo carga una u otra según el orden de lectura, lo que invalida en silencio todos los tokens OAuth2 y Actions emitidos antes de la actualización. Los usuarios ven errores de autenticación intermitentes, sin ningún mensaje que señale app.ini como causa. Elija un solo mecanismo: JWT_SECRET (valor en texto plano) o JWT_SECRET_URI (ruta hacia un archivo secreto), y elimine el otro. Reinicie el contenedor tras la modificación.

Para ir más lejos: Forgejo y CI/CD avanzado

Si desea profundizar en la automatización alrededor de su forja Git, el artículo Alojar Forgejo en su VPS detalla la configuración de una instancia Forgejo con runners Actions dedicados, la configuración del registro OCI integrado y el endurecimiento de la seguridad (fail2ban, restricción de rangos IP). Para equipos que quieran una cadena de despliegue continuo completa, es el complemento natural de esta guía.

La documentación oficial

Para la configuración avanzada y las opciones propias de la herramienta, consulte la documentación oficial de Gitea o la documentación de Forgejo. Esta guía cubre la puesta en línea en un VPS y la migración; las documentaciones de los editores siguen siendo la referencia para los ajustes finos y los casos de uso específicos.

Despliegue Gitea o Forgejo en unos minutos en un VPS Cloud de ServOrbit

Nuestro VPS Cloud, entregado con Docker preconfigurado, le permite montar su forja con SSL automático, sin manipulaciones de sistema. Recursos dedicados, snapshots e IP fija incluidos.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva