Tutorial

Instalar GitLab CE en un VPS: guía completa

Despliegue18 min de lectura9 pasos

GitHub y Bitbucket alojan sus repositorios, pero imponen sus reglas: minutos de CI racionados, propiedad del código incierta, precios que suben con el tamaño del equipo. GitLab CE (Community Edition, licencia MIT/EE Core) reúne en un solo servidor una forja git completa, un motor de CI/CD sin límite de minutos, un registry Docker privado y wikis — sin suscripción SaaS. Esta guía le muestra cómo instalarlo en menos de treinta minutos en un VPS con Docker Compose, configurar el SMTP, conectar un runner y evitar los errores clásicos: GITLAB_OMNIBUS_CONFIG mal configurado, SSL que caduca por no haber activado ACME, runner sin registrar.

Contenido· Por qué GitLab CE en lugar de GitHub o Bitbucket1/13
  1. 01Por qué GitLab CE en lugar de GitHub o Bitbucket
  2. 02Lo que GitLab CE incluye de entrada
  3. 03Requisitos previos: lo que hace falta antes de empezar
  4. 04De la instalación a su primer proyecto
  5. 05Configurar el runner Docker y escribir su primer pipeline CI/CD
  6. 06Configuración detallada del SMTP
  7. 07Copia de seguridad y restauración de GitLab
  8. 08Resolución de problemas: las tres averías más frecuentes
  9. 09Diagnóstico avanzado: Sidekiq bloqueado, timeout de Puma y OOM en Gitaly
  10. 10Seguridad: CVE-2026-90970 y actualización crítica
  11. 11Optimizar la RAM: swap y workers de Puma
  12. 12GitLab CE, Forgejo o Gitea: cómo elegir
  13. 13Cuándo elegir GitLab CE y cuándo elegir Forgejo

Por qué GitLab CE en lugar de GitHub o Bitbucket

GitHub y Bitbucket son servicios gestionados: prácticos al principio, pero su modelo de precios evoluciona con el tamaño del equipo, los minutos de CI están contados en los planes gratuitos y su código se aloja en una infraestructura de terceros. GitLab CE invierte esa ecuación: usted despliega la forja en su VPS, conserva el control total del código y de los datos, y la CI/CD va incluida sin cuota de minutos impuesta por un tercero. Para una agencia o un equipo de desarrolladores que factura a clientes o trata datos sensibles, ese control suele ser innegociable. GitLab CE es hoy una de las forjas git más desplegadas en self-hosted: su base de código es pública, su núcleo es libre y sus diez años de existencia le han dado una comunidad de colaboradores activa.

Lo que GitLab CE incluye de entrada

  • Forja git completa: repositorios privados y públicos, merge requests, revisión de código, protección de ramas y CODEOWNERS.
  • CI/CD integrada sin límite de minutos impuesto: pipelines YAML (.gitlab-ci.yml), environments, deploy tokens y artifacts.
  • Registry Docker privado alojado en su dominio: docker pull git.yourdomain.com/group/image:tag sin cuenta de Docker Hub.
  • Wikis y páginas por proyecto y por grupo, con renderizado Markdown completo.
  • Gestión de issues y milestones: tablero kanban, etiquetas, iteraciones y burndown chart incluidos.
  • Runners en paralelo: registre tantos runners como quiera en su infraestructura o en sus CI workers.
  • Webhooks para avisar a una herramienta externa (Slack, PagerDuty, su servidor de despliegue) en cada push o merge.
  • RBAC granular con cinco niveles de acceso (Guest, Reporter, Developer, Maintainer, Owner) y soporte opcional de LDAP/SAML.

Requisitos previos: lo que hace falta antes de empezar

GitLab CE consume mucha memoria — es uno de sus inconvenientes más citados frente a Forgejo o Gitea. Prevea 4 GB de RAM como mínimo para un uso ligero (menos de diez usuarios activos); se recomiendan 8 GB en cuanto añada runners en la misma máquina o active el registry Docker. Por debajo de 4 GB, Puma y Sidekiq compiten por la memoria y GitLab responde con 502 bajo carga. En disco, cuente al menos 20 GB para la instalación y los repositorios iniciales — prevea 50 GB si piensa guardar imágenes Docker en el registry. También necesita: un nombre de dominio apuntando a la IP del VPS, los puertos 80, 443 y 22 abiertos en su cortafuegos, y Docker Engine con el plugin Compose v2 instalados.

De la instalación a su primer proyecto

  1. Crear el árbol de carpetas

    Cree una carpeta dedicada y los tres volúmenes persistentes que utiliza GitLab: mkdir -p /opt/gitlab/{config,logs,data}. Sin ellas, la configuración y los repositorios desaparecen en cada docker compose down.

  2. Escribir el fichero docker-compose.yml

    Cree /opt/gitlab/docker-compose.yml. La clave GITLAB_OMNIBUS_CONFIG concentra toda la configuración específica de su instancia — sustituya git.yourdomain.com por su dominio real. Defina el servicio gitlab con la imagen gitlab/gitlab-ce:17.2.1-ce.0, restart: unless-stopped, puertos 80, 443 y 22, volúmenes, shm_size: 256m y env_file: .env.

  3. Rellenar GITLAB_OMNIBUS_CONFIG

    En GITLAB_OMNIBUS_CONFIG, defina como mínimo: external_url 'https://git.yourdomain.com'; letsencrypt['enable'] = true; parámetros SMTP — gitlab_rails['smtp_enable'] = true, dirección, puerto 587, usuario, contraseña desde ENV, autenticación login, smtp_enable_starttls_auto = true. Todas las líneas deben estar dentro del bloque GITLAB_OMNIBUS_CONFIG.

  4. Crear el fichero .env para los secretos

    Cree /opt/gitlab/.env y restrinja sus permisos: touch /opt/gitlab/.env && chmod 600 /opt/gitlab/.env. Añada GITLAB_SMTP_PASSWORD=su_contraseña_smtp. Añada .env a su .gitignore.

  5. Arrancar GitLab y esperar a la inicialización

    Lance la stack: docker compose -f /opt/gitlab/docker-compose.yml up -d. Espere unos 5 minutos antes de acceder a la interfaz web. Siga el avance con docker compose -f /opt/gitlab/docker-compose.yml logs -f gitlab y espere el mensaje gitlab Reconfigured!.

  6. Recuperar la contraseña root inicial

    Recupérela con: docker exec -it gitlab-gitlab-1 grep 'Password:' /etc/gitlab/initial_root_password. Este fichero se elimina automáticamente 24 horas después — anote la contraseña de inmediato.

  7. Conectarse, cambiar la contraseña y desactivar el registro abierto

    Abra https://git.yourdomain.com. Conéctese con root. Cambie la contraseña en User Settings → Password. Desactive el registro público en Admin Area → Settings → General → Sign-up restrictions.

  8. Registrar un GitLab Runner

    Instale gitlab-runner y recupere el token de registro en Admin Area → Runners. Registre: gitlab-runner register --url https://git.yourdomain.com --registration-token VOTRE_TOKEN --executor docker --docker-image alpine:latest.

  9. Comprobar el envío de correos

    Pruebe desde la consola Rails: docker exec -it gitlab-gitlab-1 gitlab-rails console y luego Notify.test_email('[email protected]', 'Test GitLab', 'Bonjour').deliver_now.

Copias de seguridad automáticas. GitLab incluye un comando de copia de seguridad completa: docker exec -t gitlab-gitlab-1 gitlab-backup create. Prográmelo en crontab -e con 0 3 * * * docker exec -t gitlab-gitlab-1 gitlab-backup create CRON=1. Sincronice la carpeta de archivos con un almacenamiento externo (S3, rclone) — una copia local no es una copia de seguridad.

Configurar el runner Docker y escribir su primer pipeline CI/CD

El executor Docker es el más recomendado: cada job corre en un contenedor aislado. Tras registrar el runner, su fichero /etc/gitlab-runner/config.toml contiene un bloque [runners.docker]. Añada volumes = ["/cache"] y pull_policy = ["if-not-present"] para acelerar los builds.

Ejemplo de pipeline básico en .gitlab-ci.yml:

stages:
  - test
  - build
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

test:unit:
  stage: test
  image: node:20-alpine
  cache:
    key: $CI_COMMIT_REF_SLUG
    paths:
      - node_modules/
  script:
    - npm ci
    - npm test
  only:
    - merge_requests
    - main

build:image:
  stage: build
  image: docker:26
  services:
    - docker:26-dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE
  only:
    - main

deploy:prod:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
  script:
    - ssh -o StrictHostKeyChecking=no [email protected] "docker pull $DOCKER_IMAGE && docker compose up -d"
  only:
    - main
  when: manual

Las variables CI_REGISTRY_USER, CI_REGISTRY_PASSWORD y CI_REGISTRY se inyectan automáticamente por GitLab CE. La variable SSH_PRIVATE_KEY se define en Settings → CI/CD → Variables marcada como Masked. El job deploy:prod tiene when: manual — no se dispara automáticamente.

Configuración detallada del SMTP

GitLab envía correos en cada merge request, mención, pipeline completado o alerta de seguridad. Una configuración SMTP ausente o errónea corta silenciosamente esas notificaciones.

Bloque completo en GITLAB_OMNIBUS_CONFIG para un relay SMTP autenticado (STARTTLS, puerto 587):

gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = 'smtp.yourdomain.com'
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = '[email protected]'
gitlab_rails['smtp_password'] = ENV['GITLAB_SMTP_PASSWORD']
gitlab_rails['smtp_authentication'] = 'login'
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['gitlab_email_from'] = '[email protected]'
gitlab_rails['gitlab_email_reply_to'] = '[email protected]'

Para TLS directo (puerto 465), sustituya smtp_enable_starttls_auto = true por smtp_tls = true. Las claves fuera del bloque omnibus se ignoran en silencio — pruebe siempre con Notify.test_email(…).deliver_now desde la consola Rails.

Copia de seguridad y restauración de GitLab

El comando docker exec -t gitlab-gitlab-1 gitlab-backup create genera un tar completo con repositorios, base de datos PostgreSQL y artifacts. Importante: no incluye /etc/gitlab/gitlab.rb ni /etc/gitlab/gitlab-secrets.json — guárdelos por separado:

tar czf /opt/gitlab/config-secrets-$(date +%Y%m%d).tar.gz \
  /opt/gitlab/config/gitlab.rb \
  /opt/gitlab/config/gitlab-secrets.json

Restauración en tres pasos: instale la misma versión menor que produjo la copia; copie el tar en /opt/gitlab/data/backups/; luego:

docker exec -it gitlab-gitlab-1 gitlab-ctl stop puma
docker exec -it gitlab-gitlab-1 gitlab-ctl stop sidekiq
docker exec -it gitlab-gitlab-1 gitlab-backup restore BACKUP=<timestamp>_<version>
docker exec -it gitlab-gitlab-1 gitlab-ctl restart
docker exec -it gitlab-gitlab-1 gitlab-rake gitlab:check SANITIZE=true

Planifique la copia a las 3 de la madrugada y sincronice a almacenamiento externo.

Resolución de problemas: las tres averías más frecuentes

502 Bad Gateway al arrancar. GitLab tarda unos 5 minutos en estar plenamente operativo. Si el 502 persiste, compruebe que Puma ha arrancado: docker exec gitlab-gitlab-1 gitlab-ctl status puma. La falta de RAM es la causa más frecuente. El SMTP no funciona. Verifique que el bloque gitlab_rails['smtp_*'] esté dentro de GITLAB_OMNIBUS_CONFIG — una clave fuera del bloque es un fallo silencioso. Runner no conectado. Compruebe con gitlab-runner verify --url https://git.yourdomain.com. Un certificado TLS autofirmado o un DNS no resoluble desde la máquina del runner son las causas habituales.

Diagnóstico avanzado: Sidekiq bloqueado, timeout de Puma y OOM en Gitaly

Sidekiq queue stuck. Compruebe el estado:

docker exec gitlab-gitlab-1 gitlab-ctl status sidekiq
docker exec gitlab-gitlab-1 gitlab-rake gitlab:sidekiq:check

Para vaciar una cola sin reiniciar: docker exec -it gitlab-gitlab-1 gitlab-rails console -e production luego Sidekiq::Queue.new('mailers').clear. Para reiniciarlo sin perder jobs pendientes: docker exec gitlab-gitlab-1 gitlab-ctl restart sidekiq.

Timeout de Puma. Añada en GITLAB_OMNIBUS_CONFIG: puma['worker_timeout'] = 90 (predeterminado 60 s). Si persisten los timeouts, la causa casi siempre es falta de RAM o un número de workers inadecuado.

OOM en Gitaly. Verifique con dmesg | grep -i kill. Reduzca la caché: gitaly['configuration']['git']['catfile_cache_size'] = 5 (predeterminado 100).

Contenedor que sale al arrancar. Revise los logs: docker compose logs gitlab | tail -50. Causas frecuentes: conflicto en el puerto 22, volumen no escribible o sintaxis Ruby inválida en GITLAB_OMNIBUS_CONFIG.

Seguridad: CVE-2026-90970 y actualización crítica

El 2 de octubre de 2026, GitLab divulgó CVE-2026-90970, una vulnerabilidad crítica (CVSS 9.9) que afecta al componente AI Gateway de los despliegues self-hosted. El fallo es una inyección de plantillas en el lado del servidor (SSTI) en los templates de flujo personalizados: un usuario autenticado con acceso a la plataforma Duo Agent puede enviar una configuración de flujo especialmente diseñada para escapar del sandbox y ejecutar comandos arbitrarios en el host subyacente.

Qué está afectado. Únicamente las instancias self-hosted que despliegan el componente AI Gateway. GitLab.com y las instancias Dedicated ya fueron parcheadas automáticamente. La explotación requiere acceso a Duo Agent Platform y no se han notificado ataques en la naturaleza en el momento de la divulgación.

Versiones vulnerables y versiones corregidas.

| Rama | Última versión vulnerable | Versión corregida |
|---|---|---|
| 19.4.x | 19.4.0 | 19.4.1 |
| 19.3.x | 19.3.1 | 19.3.2 |
| 18.1.6 – 19.2.x | 19.2.3 | 19.2.4 |

Actualizar el AI Gateway en Docker.

# Detener y eliminar el contenedor existente
docker stop gitlab-ai-gateway && docker rm gitlab-ai-gateway

# Descargar la imagen corregida (sustituya el tag por su rama)
docker pull registry.gitlab.com/gitlab-org/modelops/apigw/self-hosted-v19.4.1-ee
# o: self-hosted-v19.3.2-ee / self-hosted-v19.2.4-ee

# Reiniciar con las mismas variables de entorno
docker run -d --name gitlab-ai-gateway \
  --restart unless-stopped \
  [sus opciones habituales] \
  registry.gitlab.com/gitlab-org/modelops/apigw/self-hosted-v19.4.1-ee

# Verificar la versión desplegada
docker ps --format '{{.Image}}' | grep ai-gateway

Actualizar mediante Helm / Kubernetes. Actualice image.tag en sus values de Helm a la versión corregida, configure imagePullPolicy: Always y ejecute helm upgrade.

Tras la actualización, confirme que el contenedor usa la imagen parcheada: docker inspect <container> --format '{{.Config.Image}}'.

Deshabilitar el AI Gateway si no lo utiliza. Si su instancia de GitLab CE no usa las funciones Duo (completado de código con IA, chat), el AI Gateway puede simplemente detenerse y eliminarse de su docker-compose.yml. Un componente no desplegado no puede ser explotado. Verifique que ningún pipeline dependa del AI Gateway API antes de eliminarlo.

Optimizar la RAM: swap y workers de Puma

Reducir workers de Puma. En GITLAB_OMNIBUS_CONFIG:

puma['worker_processes'] = 2
puma['min_threads'] = 1
puma['max_threads'] = 4

Cada worker Puma consume entre 200 y 300 MB. Dos workers son suficientes para menos de quince usuarios activos simultáneos.

Añadir swap. En un VPS sin swap preconfigurado:

fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

Recomendaciones de RAM y CPU por tamaño de equipo

| Tamaño del equipo | RAM recomendada | vCPU | Notas |
|---|---|---|---|
| 1–5 desarrolladores | 4 GB | 2 | Runners en la misma máquina posibles con swap |
| 5–15 desarrolladores | 8 GB | 4 | Runner dedicado aconsejable a partir de 8+ pipelines/día |
| 15–30 desarrolladores | 16 GB | 8 | Registry Docker activo, Gitaly bajo carga |
| 30+ desarrolladores | 32 GB+ | 16+ | Separar Gitaly y Sidekiq en máquinas dedicadas |

GitLab CE, Forgejo o Gitea: cómo elegir

Desplace la tabla

CriterioGitLab CEForgejo / Gitea
LicenciaMIT / EE CoreMIT
RAM en reposo300–600 MB (Puma + Sidekiq)30–50 MB
CI/CD nativaSí (`.gitlab-ci.yml`, runners)Forgejo: sí mediante Woodpecker CI; Gitea: no nativa
Registry Docker integradoSíForgejo: sí; Gitea: no nativo
Wikis por proyectoSíSí
LDAP / SAMLSí (CE)Forgejo: sí; Gitea: LDAP sí, SAML no
Curva de aprendizajeAlta (interfaz rica)De baja a media
Ideal paraEquipos de 5+ con CI, registry y RBACEquipos ligeros, forja simple, poca huella de RAM

Cuándo elegir GitLab CE y cuándo elegir Forgejo

GitLab CE es la elección correcta si su equipo necesita una CI/CD robusta directamente integrada en la forja, un registry Docker privado en su dominio, pipelines de despliegue con environments y deploy tokens, o una gestión de proyecto con issues, milestones y kanban sin herramienta externa. Su huella de memoria (4–8 GB) es el precio de esa riqueza funcional. Forgejo o Gitea se imponen cuando la memoria es la restricción principal, cuando la forja es la única necesidad (sin CI integrada). En un VPS de 2 GB, GitLab CE no es viable; Forgejo funciona con 256 MB. En un VPS de 8 GB dedicado a un equipo de desarrolladores, GitLab CE ofrece un entorno completo equivalente al que GitHub pone en su plataforma SaaS — bajo su control y sin suscripción mensual por usuario.

Un VPS listo para GitLab CE

GitLab CE necesita un VPS de 4 a 8 GB de RAM, un disco generoso y una IP dedicada. Nuestros VPS ServOrbit se entregan con el sistema que elija entre Ubuntu 24.04 LTS, Ubuntu 22.04 LTS y Debian 12 y acceso root inmediato — suficiente para tener su forja en línea en treinta minutos.

¿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