Proyecto guiado: servidor GitLab personal con Docker Compose

1. Objetivo del proyecto

El objetivo es instalar un servidor GitLab Self-Managed sobre una máquina con Ubuntu Server.

Este servidor permitirá:

  • Guardar proyectos de programación.
  • Centralizar scripts personales.
  • Mantener archivos de configuración.
  • Trabajar desde diferentes ordenadores.
  • Controlar las versiones de los archivos.
  • Recuperar versiones anteriores.
  • Desplegar proyectos en otros servidores.
  • Automatizar despliegues mediante GitLab CI/CD.
  • Mantener copias de seguridad de todos los repositorios.

Aunque muchas veces se utiliza la expresión “instalar un GitHub”, realmente instalaremos GitLab, que ofrece un servicio similar a GitHub, pero alojado en nuestro propio servidor.

La arquitectura inicial será:

Ordenador personal
        │
        │ Git mediante SSH o HTTPS
        ▼
https://gitlab.tudominio.es
        │
        ▼
Router de Internet
        │
        │ Puertos 80, 443 y 2222
        ▼
Ubuntu Server
        │
        ▼
Docker Compose
        │
        ▼
GitLab Community Edition

Fase 0. Planificación y requisitos

0.1. Requisitos recomendados

Para una instalación personal se recomienda:

  • Ubuntu Server 22.04 LTS o 24.04 LTS.
  • Procesador de 64 bits.
  • 4 núcleos de CPU recomendados.
  • 8 GB de RAM recomendados.
  • 50 GB de almacenamiento como mínimo.
  • Dirección IP local fija.
  • Dominio propio.
  • Acceso a la configuración del router.
  • Conexión a Internet sin CG-NAT, o con posibilidad de abrir puertos.
  • Usuario de Ubuntu con permisos sudo.

GitLab consume bastantes más recursos que un servidor Git básico. Con 4 GB de RAM puede funcionar para pruebas, pero para un uso continuado es preferible disponer de 8 GB o más.

0.2. Datos utilizados en los ejemplos

Durante la documentación utilizaremos estos datos:

Dominio: gitlab.tudominio.es
IP local del servidor: 192.168.1.50
Puerto web HTTP: 80
Puerto web HTTPS: 443
Puerto SSH de GitLab: 2222
Directorio de instalación: /srv/gitlab

El puerto SSH externo será el 2222 porque el puerto 22 normalmente ya está siendo utilizado por el servicio SSH de Ubuntu Server.

0.3. Comprobar la versión de Ubuntu

lsb_release -a

También podemos utilizar:

cat /etc/os-release

0.4. Comprobar procesador, memoria y almacenamiento

Procesador:

lscpu

Memoria:

free -h

Espacio en disco:

df -h

0.5. Actualizar Ubuntu Server

sudo apt update
sudo apt upgrade -y

Reiniciamos si se ha actualizado el kernel:

sudo reboot

Fase 1. Configuración de red y dominio

1.1. Asignar una IP fija al servidor

El servidor debe mantener siempre la misma dirección IP dentro de la red local.

Tenemos dos posibilidades:

  1. Crear una reserva DHCP en el router.
  2. Configurar una IP estática en Ubuntu Server.

La opción más sencilla suele ser crear una reserva DHCP en el router asociando la dirección MAC del servidor con una IP, por ejemplo:

192.168.1.50

Para consultar la dirección IP actual:

ip address

Versión abreviada:

ip -br address

Para conocer la puerta de enlace:

ip route

1.2. Comprobar la IP pública

Desde el servidor podemos ejecutar:

curl https://ifconfig.me

También podemos consultar la IP pública desde el panel del router.

1.3. Crear el registro DNS

En el proveedor del dominio debemos crear un registro de tipo A.

Ejemplo:

Tipo: A
Nombre: gitlab
Destino: IP_PUBLICA
TTL: Automático

El resultado será:

gitlab.tudominio.es → IP pública del router

Si la conexión utiliza una IP pública dinámica, será necesario configurar un servicio de DNS dinámico o actualizar automáticamente el registro DNS.

El dominio debe resolver públicamente hacia el servidor para que GitLab pueda solicitar automáticamente el certificado HTTPS de Let’s Encrypt.

1.4. Comprobar la resolución DNS

Desde otro ordenador:

nslookup gitlab.tudominio.es

En Linux o macOS también podemos utilizar:

dig gitlab.tudominio.es

El resultado debe mostrar nuestra IP pública.

1.5. Configurar la redirección de puertos

En el router debemos crear estas reglas NAT o Port Forwarding:

Puerto externoIP internaPuerto internoProtocolo
80192.168.1.5080TCP
443192.168.1.50443TCP
2222192.168.1.502222TCP

Los puertos 80 y 443 deben ser accesibles desde Internet para la validación y renovación automática del certificado de Let’s Encrypt.

1.6. Comprobar si existe CG-NAT

Compara:

  • La IP pública mostrada por el router.
  • La IP obtenida con curl https://ifconfig.me.

Si son diferentes, es posible que la conexión esté detrás de CG-NAT.

En ese caso, las redirecciones de puertos no funcionarán directamente. Las alternativas serían:

  • Solicitar una IP pública al proveedor.
  • Utilizar una VPN como WireGuard o Tailscale.
  • Utilizar un túnel inverso.
  • Alojar GitLab en un VPS.

Fase 2. Instalación de Docker y Docker Compose

2.1. Eliminar paquetes incompatibles

Antes de instalar Docker desde su repositorio oficial eliminamos posibles versiones anteriores:

sudo apt remove -y \
docker.io \
docker-compose \
docker-compose-v2 \
docker-doc \
podman-docker \
containerd \
runc

No ocurre nada si algunos de estos paquetes no estaban instalados.

Docker recomienda utilizar su repositorio oficial de APT e instalar el complemento moderno docker compose, en lugar del antiguo ejecutable independiente docker-compose.

2.2. Instalar las dependencias

sudo apt update
sudo apt install -y ca-certificates curl

2.3. Añadir la clave oficial de Docker

sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL \
https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

2.4. Añadir el repositorio

sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

Actualizamos la información de paquetes:

sudo apt update

2.5. Instalar Docker

sudo apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin

2.6. Comprobar el servicio

sudo systemctl status docker

Debe aparecer:

active (running)

Para salir de la pantalla de estado pulsamos:

q

2.7. Activar Docker durante el arranque

sudo systemctl enable docker

2.8. Probar Docker

sudo docker run --rm hello-world

2.9. Comprobar Docker Compose

sudo docker compose version

Debe aparecer una versión de Docker Compose.

2.10. Permitir utilizar Docker sin sudo

Añadimos nuestro usuario al grupo docker:

sudo usermod -aG docker "$USER"

Cerramos la sesión cambiado de usuario o reiniciando.

Volvemos a conectarnos por SSH y comprobamos:

docker ps

Pertenecer al grupo docker proporciona privilegios elevados sobre el sistema. Solamente deben añadirse usuarios de confianza.


Fase 3. Preparación del servidor GitLab

3.1. Crear la estructura de directorios

sudo mkdir -p /srv/gitlab

Creamos los directorios persistentes:

sudo mkdir -p /srv/gitlab/config
sudo mkdir -p /srv/gitlab/logs
sudo mkdir -p /srv/gitlab/data
sudo mkdir -p /srv/gitlab/backups

Asignamos los directorios al usuario actual:

sudo chown -R "$USER":"$USER" /srv/gitlab

Entramos en el directorio:

cd /srv/gitlab

3.2. Función de los directorios

Directorio del servidorDirectorio del contenedorContenido
/srv/gitlab/config/etc/gitlabConfiguración y secretos
/srv/gitlab/logs/var/log/gitlabRegistros
/srv/gitlab/data/var/opt/gitlabRepositorios y datos
/srv/gitlab/backupsCopias adicionales

La imagen oficial de GitLab utiliza precisamente /etc/gitlab, /var/log/gitlab y /var/opt/gitlab para conservar la configuración, los registros y los datos.


Fase 4. Instalación de GitLab con Docker Compose

4.1. Elegir una versión

GitLab ofrece:

  • GitLab Community Edition: gitlab/gitlab-ce
  • GitLab Enterprise Edition: gitlab/gitlab-ee

Para este proyecto personal utilizaremos Community Edition.

Para una primera prueba se puede utilizar:

gitlab/gitlab-ce:latest

Sin embargo, cuando el servidor esté funcionando conviene fijar una versión concreta:

gitlab/gitlab-ce:19.x.x-ce.0

GitLab recomienda fijar una versión específica en entornos estables y utilizar latest principalmente para pruebas.

4.2. Crear el archivo .env

nano /srv/gitlab/.env

Contenido:

GITLAB_HOSTNAME=gitlab.tudominio.es
GITLAB_IMAGE=gitlab/gitlab-ce:latest

Guardamos con:

Ctrl + O
Enter
Ctrl + X

4.3. Crear compose.yaml

nano /srv/gitlab/compose.yaml

Contenido:

services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    container_name: gitlab
    hostname: 192.168.1.14
    restart: unless-stopped

    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://192.168.1.14:8929'

        nginx['listen_port'] = 80
        nginx['listen_https'] = false
        letsencrypt['enable'] = false

        gitlab_rails['gitlab_shell_ssh_port'] = 2222

    ports:
      - "8929:80"
      - "2222:22"

    volumes:
      - ./config:/etc/gitlab
      - ./logs:/var/log/gitlab
      - ./data:/var/opt/gitlab

    shm_size: "256m"

La configuración utiliza:

Puerto 80 del servidor  → puerto 80 de GitLab
Puerto 443 del servidor → puerto 443 de GitLab
Puerto 2222 del servidor → puerto 22 del contenedor

El valor:

gitlab_rails['gitlab_shell_ssh_port'] = 2222

indica a GitLab que debe mostrar el puerto 2222 en las direcciones de clonación SSH. La documentación oficial contempla configurar un puerto SSH externo diferente cuando el puerto 22 del servidor está ocupado.

4.4. Validar el archivo

cd /srv/gitlab
docker compose config

Si no aparecen errores, la sintaxis es correcta.

4.5. Descargar la imagen

docker compose pull

4.6. Iniciar GitLab

docker compose up -d

4.7. Consultar el estado

docker compose ps

4.8. Consultar los registros

docker compose logs -f gitlab

Para dejar de visualizar los registros:

Ctrl + C

La primera inicialización es más lenta que los siguientes arranques porque GitLab debe configurar PostgreSQL, Redis, NGINX, Gitaly y el resto de sus componentes internos.

4.9. Comprobar el estado interno

docker exec -it gitlab gitlab-ctl status

También podemos comprobar el endpoint de estado:

curl -I https://gitlab.tudominio.es

Fase 5. Primer acceso y configuración inicial

5.1. Obtener la contraseña inicial

docker exec -it gitlab \
grep 'Password:' /etc/gitlab/initial_root_password

El usuario inicial es:

root

El archivo con la contraseña inicial se elimina automáticamente después del primer reinicio transcurridas aproximadamente 24 horas, por lo que conviene obtenerla y cambiarla cuanto antes.

5.2. Entrar en GitLab

Revisa la configuración persistente

Como /srv/gitlab/config es persistente, puede conservarse la dirección anterior.

Ejecuta:

grep -n "external_url" /srv/gitlab/config/gitlab.rb

Si aparece:

external_url 'https://gitlab.tudominio.es'

edita el archivo:

sudo nano /srv/gitlab/config/gitlab.rb

Cámbialo por:

external_url 'http://192.168.1.14:8929'

Introducimos:

Usuario: root
Contraseña: la obtenida anteriormente

5.3. Cambiar la contraseña de root

Dentro de GitLab:

Avatar
→ Edit profile
→ Password

Debemos utilizar una contraseña larga y exclusiva.

5.4. Crear un usuario personal

Es preferible no trabajar diariamente con root.

Entramos en:

Admin
→ Overview
→ Users
→ New user

Ejemplo:

Nombre: Antonio Otero
Usuario: antonio
Correo: correo@tudominio.es

Podemos marcar el usuario como administrador si realmente necesitamos administrar GitLab desde esa cuenta.

5.5. Desactivar el registro público

Como el servidor está expuesto a Internet y será de uso personal, debemos impedir que cualquier visitante pueda crear una cuenta.

Ruta:

Admin
→ Settings
→ General
→ New user account restrictions

Desmarcamos:

Allow new user accounts

GitLab recomienda plantearse la desactivación del registro en instancias públicas donde no se espera que usuarios externos creen cuentas.

5.6. Limitar la visibilidad predeterminada

En:

Admin
→ Settings
→ General
→ Visibility and access controls

Configuramos:

Default project visibility: Private
Default snippet visibility: Private
Default group visibility: Private

5.7. Activar autenticación de dos factores

En la cuenta personal:

Avatar
→ Edit profile
→ Account
→ Two-factor authentication

Guardamos los códigos de recuperación en un lugar seguro.


Fase 6. Configuración de Git y claves SSH

GitLab permite trabajar mediante HTTPS o SSH. Para trabajar habitualmente desde varios equipos utilizaremos SSH, que GitLab recomienda como método de autenticación para clonar repositorios.

6.1. Instalar Git en Ubuntu o Debian

sudo apt update
sudo apt install -y git

6.2. Instalar Git en Windows

Puede instalarse Git for Windows y utilizar:

  • Git Bash.
  • PowerShell.
  • Visual Studio Code.
  • Un IDE compatible con Git.

6.3. Comprobar la instalación

git --version

6.4. Configurar el nombre y el correo

En cada ordenador:

git config --global user.name "Antonio Otero"
git config --global user.email "correo@tudominio.es"

Comprobamos:

git config --global --list

6.5. Crear una clave SSH

En Linux, macOS, PowerShell o Git Bash:

ssh-keygen -t ed25519 -C "portatil-personal"

Cuando pregunte dónde guardar la clave, pulsamos Enter.

Ruta habitual:

Linux/macOS:
~/.ssh/id_ed25519
~/.ssh/id_ed25519.pub

Windows:
C:\Users\USUARIO\.ssh\id_ed25519
C:\Users\USUARIO\.ssh\id_ed25519.pub

Es recomendable establecer una contraseña para proteger la clave privada.

6.6. Mostrar la clave pública

Linux o macOS:

cat ~/.ssh/id_ed25519.pub

Windows PowerShell:

Get-Content $HOME\.ssh\id_ed25519.pub

Copiamos el contenido completo.

6.7. Añadir la clave a GitLab

En GitLab:

Avatar
→ Edit profile
→ Access
→ SSH keys
→ Add new key

Indicamos un nombre identificativo:

MacBook Pro
PC principal
Portátil Windows
Equipo del trabajo

Cada ordenador debe tener su propia clave. No es recomendable copiar la misma clave privada entre todos los equipos.

6.8. Configurar el puerto SSH personalizado

Creamos o editamos:

nano ~/.ssh/config

Contenido:

Host gitlab-personal
    HostName gitlab.tudominio.es
    User git
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Protegemos el archivo:

chmod 600 ~/.ssh/config

6.9. Probar la conexión

ssh -T gitlab-personal

La primera vez aparecerá una pregunta sobre la huella del servidor.

Después de comprobar que el nombre del servidor es correcto, respondemos:

yes

El resultado esperado será parecido a:

Welcome to GitLab, @antonio!

También podemos probar directamente:

ssh -T -p 2222 git@gitlab.tudominio.es

Fase 7. Crear y utilizar el primer repositorio

7.1. Crear un proyecto en GitLab

Entramos en:

New project
→ Create blank project

Ejemplo:

Project name: scripts-linux
Project slug: scripts-linux
Visibility level: Private

Podemos marcar:

Initialize repository with a README

7.2. Clonar el repositorio

Utilizando el alias SSH:

git clone gitlab-personal:antonio/scripts-linux.git

Entramos en el proyecto:

cd scripts-linux

7.3. Crear un archivo

nano informacion-sistema.sh

Contenido:

#!/bin/bash

echo "Nombre del equipo:"
hostname

echo
echo "Sistema operativo:"
cat /etc/os-release

echo
echo "Memoria:"
free -h

echo
echo "Almacenamiento:"
df -h

Guardamos y damos permisos:

chmod +x informacion-sistema.sh

7.4. Consultar el estado

git status

7.5. Añadir los cambios

git add informacion-sistema.sh

También podríamos añadir todos los archivos:

git add .

7.6. Crear un commit

git commit -m "Añadido script de información del sistema"

7.7. Subir los cambios

git push

7.8. Flujo de trabajo habitual

Cada vez que comencemos a trabajar:

git pull

Después modificamos los archivos y ejecutamos:

git status
git add .
git commit -m "Descripción clara de los cambios"
git push

Fase 8. Trabajar desde varios ordenadores

8.1. Primer ordenador

En el primer equipo:

git clone gitlab-personal:antonio/scripts-linux.git
cd scripts-linux

Modificamos y subimos cambios:

git add .
git commit -m "Cambios realizados desde el PC principal"
git push

8.2. Segundo ordenador

Configuramos su propia clave SSH y la añadimos a GitLab.

Después:

git clone gitlab-personal:antonio/scripts-linux.git
cd scripts-linux

Antes de trabajar:

git pull

Realizamos los cambios:

git add .
git commit -m "Cambios realizados desde el portátil"
git push

8.3. Regla fundamental

Antes de empezar una sesión de trabajo:

git pull

Después de terminar:

git add .
git commit -m "Explicación de los cambios"
git push

8.4. Evitar conflictos

No conviene modificar simultáneamente las mismas líneas del mismo archivo desde dos equipos sin haber sincronizado antes.

Flujo recomendado:

git pull

Trabajamos.

git add .
git commit -m "Cambios"
git push

8.5. Resolver un conflicto sencillo

Si git pull detecta un conflicto, el archivo mostrará algo parecido a:

<<<<<<< HEAD
Contenido local
=======
Contenido procedente del servidor
>>>>>>> origin/main

Debemos editar el archivo y dejar solamente el contenido definitivo.

Después:

git add archivo-conflictivo
git commit -m "Resuelto conflicto de sincronización"
git push

Fase 9. Organización de los repositorios personales

Para mantener el servidor ordenado podemos crear un grupo llamado:

personal

Dentro del grupo podemos crear repositorios como:

personal/scripts-linux
personal/scripts-windows
personal/docker-compose
personal/configuraciones
personal/wordpress
personal/php
personal/java
personal/python
personal/documentacion
personal/proyectos-clase

9.1. Qué debe guardarse

Ejemplos adecuados:

  • Código fuente.
  • Scripts Bash.
  • Scripts PowerShell.
  • Archivos Docker Compose.
  • Plantillas HTML y CSS.
  • Documentación Markdown.
  • Configuraciones sin credenciales.
  • Proyectos Java, PHP, Python o JavaScript.
  • Consultas SQL.
  • Diagramas.
  • Archivos pequeños relacionados con el proyecto.

9.2. Qué no debe guardarse directamente

No deben subirse:

  • Contraseñas.
  • Claves privadas SSH.
  • Tokens de acceso.
  • Archivos .env con credenciales.
  • Copias completas de bases de datos con datos sensibles.
  • Directorios de dependencias regenerables.
  • Imágenes de máquinas virtuales.
  • Archivos temporales.
  • Copias de seguridad grandes.
  • Certificados privados.

9.3. Utilizar .gitignore

Ejemplo para un proyecto PHP:

.env
vendor/
node_modules/
*.log
.DS_Store
.vscode/
.idea/

Ejemplo para Java:

target/
bin/
.classpath
.project
.settings/
*.class
*.jar
.idea/

Ejemplo para Python:

__pycache__/
*.pyc
.venv/
venv/
.env

Fase 10. Importar un proyecto existente

Supongamos que tenemos un proyecto en:

/home/antonio/proyectos/mi-web

Entramos en él:

cd /home/antonio/proyectos/mi-web

Inicializamos Git:

git init

Creamos la rama principal:

git branch -M main

Añadimos los archivos:

git add .

Creamos el primer commit:

git commit -m "Importación inicial del proyecto"

Creamos un proyecto vacío en GitLab y añadimos el remoto:

git remote add origin \
ssh://git@gitlab.tudominio.es:2222/antonio/mi-web.git

Subimos el proyecto:

git push -u origin main

Para consultar el remoto:

git remote -v

Fase 11. Despliegue manual en otro ordenador

GitLab almacenará el proyecto, pero también queremos desplegarlo en otros servidores.

Supongamos que tenemos un servidor web con Ubuntu en:

192.168.1.80

11.1. Instalar Git en el servidor destino

sudo apt update
sudo apt install -y git

11.2. Crear una clave exclusiva de despliegue

En el servidor destino:

ssh-keygen -t ed25519 -C "despliegue-servidor-web"

Mostramos la clave pública:

cat ~/.ssh/id_ed25519.pub

11.3. Añadir una Deploy Key

En el proyecto de GitLab:

Settings
→ Repository
→ Deploy keys
→ Add new key

Introducimos:

Title: Servidor web
Key: contenido de id_ed25519.pub

Para un despliegue que solamente descarga archivos, no activamos permisos de escritura.

Las Deploy Keys están pensadas precisamente para permitir que servidores externos accedan a repositorios sin asociar el acceso a la clave personal de un usuario.

11.4. Configurar SSH en el servidor destino

nano ~/.ssh/config

Contenido:

Host gitlab-personal
    HostName gitlab.tudominio.es
    User git
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Permisos:

chmod 600 ~/.ssh/config

11.5. Clonar el proyecto

sudo mkdir -p /var/www
sudo chown "$USER":"$USER" /var/www
cd /var/www
git clone gitlab-personal:antonio/mi-web.git

11.6. Actualizar el despliegue

Cuando subamos cambios a GitLab:

cd /var/www/mi-web
git pull origin main

Este sería el despliegue manual más sencillo.


Fase 12. Crear un script de despliegue

En el servidor destino:

sudo nano /usr/local/bin/desplegar-mi-web.sh

Contenido:

#!/bin/bash

set -e

PROYECTO="/var/www/mi-web"
RAMA="main"

echo "Iniciando despliegue..."

cd "$PROYECTO"

echo "Descargando cambios..."
git fetch origin

echo "Actualizando la rama $RAMA..."
git reset --hard "origin/$RAMA"

echo "Corrigiendo permisos..."
sudo chown -R www-data:www-data "$PROYECTO"

echo "Despliegue terminado correctamente."

Damos permisos:

sudo chmod +x /usr/local/bin/desplegar-mi-web.sh

Ejecutamos:

sudo /usr/local/bin/desplegar-mi-web.sh

El uso de:

git reset --hard origin/main

garantiza que el directorio desplegado coincida exactamente con el contenido del repositorio remoto.

Debe utilizarse solamente en un directorio de despliegue donde no se hagan cambios manuales que queramos conservar.


Fase 13. Introducción al despliegue automático con GitLab Runner

En una fase posterior podemos automatizar el despliegue mediante GitLab CI/CD.

El flujo será:

Ordenador
   │
   │ git push
   ▼
GitLab
   │
   │ Ejecuta pipeline
   ▼
GitLab Runner
   │
   │ Conecta por SSH
   ▼
Servidor de despliegue

GitLab Runner puede ejecutarse dentro de un contenedor Docker y ejecutar los trabajos definidos en .gitlab-ci.yml.

13.1. Ejemplo conceptual de .gitlab-ci.yml

stages:
  - comprobar
  - desplegar

comprobar:
  stage: comprobar
  script:
    - echo "Comprobando el proyecto"
    - test -f index.html

desplegar:
  stage: desplegar
  script:
    - echo "Desplegando proyecto"
    - ssh usuario@servidor-destino "/usr/local/bin/desplegar-mi-web.sh"
  only:
    - main

Las claves privadas utilizadas por CI/CD no deben ser las claves personales del usuario. GitLab recomienda utilizar claves específicas para la automatización y almacenarlas de forma protegida.

La instalación y configuración completa de Runner debe realizarse como una fase independiente después de dominar:

  • Repositorios.
  • Clonado.
  • Commits.
  • Push y pull.
  • Claves SSH.
  • Deploy Keys.
  • Despliegue manual.

Fase 14. Copias de seguridad

Un repositorio Git distribuido ya proporciona copias parciales en los equipos donde se ha clonado, pero eso no sustituye una copia completa de GitLab.

La copia de GitLab debe incluir:

  • Base de datos.
  • Repositorios.
  • Archivos subidos.
  • Configuración.
  • Secretos.
  • Certificados.
  • Archivo compose.yaml.
  • Archivo .env.

GitLab advierte de que debe conservarse también gitlab-secrets.json, porque contiene secretos necesarios para descifrar determinados datos durante una recuperación.

14.1. Crear una copia desde el contenedor

docker exec -t gitlab gitlab-backup create

La copia se guardará normalmente dentro de:

/srv/gitlab/data/backups

Consultamos:

sudo ls -lh /srv/gitlab/data/backups

14.2. Copiar la configuración

Creamos una carpeta con la fecha:

FECHA=$(date +%Y-%m-%d_%H-%M)
mkdir -p "/srv/gitlab/backups/$FECHA"

Copiamos la configuración:

sudo cp -a \
/srv/gitlab/config \
"/srv/gitlab/backups/$FECHA/"

Copiamos Compose y las variables:

cp /srv/gitlab/compose.yaml \
"/srv/gitlab/backups/$FECHA/"
cp /srv/gitlab/.env \
"/srv/gitlab/backups/$FECHA/"

14.3. Crear un archivo comprimido

cd /srv/gitlab/backups
sudo tar -czf "gitlab-config-$FECHA.tar.gz" "$FECHA"

14.4. Copia externa

La copia debe trasladarse a otro equipo o almacenamiento:

rsync -avh \
/srv/gitlab/backups/ \
usuario@servidor-copias:/copias/gitlab/

También se puede utilizar:

  • NAS.
  • Disco USB.
  • Otro servidor.
  • Almacenamiento cifrado en la nube.
  • rclone.
  • Copia mediante scp.

Una copia guardada únicamente en el mismo disco que GitLab no protege frente a una avería física de ese disco.


Fase 15. Automatizar las copias

15.1. Crear un script

sudo nano /usr/local/sbin/copiar-gitlab.sh

Contenido:

#!/bin/bash

set -euo pipefail

FECHA=$(date +%Y-%m-%d_%H-%M-%S)
ORIGEN="/srv/gitlab"
DESTINO="/srv/gitlab/backups/$FECHA"

echo "Creando copia interna de GitLab..."

docker exec -t gitlab gitlab-backup create

echo "Copiando configuración..."

mkdir -p "$DESTINO"

cp -a "$ORIGEN/config" "$DESTINO/"
cp "$ORIGEN/compose.yaml" "$DESTINO/"
cp "$ORIGEN/.env" "$DESTINO/"

echo "Comprimiendo configuración..."

tar -czf "/srv/gitlab/backups/gitlab-config-$FECHA.tar.gz" \
-C "/srv/gitlab/backups" "$FECHA"

rm -rf "$DESTINO"

echo "Eliminando copias de configuración antiguas..."

find /srv/gitlab/backups \
-type f \
-name "gitlab-config-*.tar.gz" \
-mtime +14 \
-delete

echo "Copia terminada: $FECHA"

Damos permisos:

sudo chmod 700 /usr/local/sbin/copiar-gitlab.sh

15.2. Probar el script

sudo /usr/local/sbin/copiar-gitlab.sh

15.3. Programarlo con cron

sudo crontab -e

Añadimos:

0 3 * * * /usr/local/sbin/copiar-gitlab.sh >> /var/log/copiar-gitlab.log 2>&1

Esto ejecutará la copia todos los días a las 03:00.


Fase 16. Restauración básica

La restauración debe probarse antes de depender de ella.

GitLab exige que la instalación utilizada para restaurar tenga la misma versión y edición que la instalación que creó la copia.

16.1. Consultar la versión instalada

docker exec -it gitlab gitlab-rake gitlab:env:info

También podemos consultar la imagen:

docker inspect gitlab \
--format='{{.Config.Image}}'

Debemos anotar el resultado.

Ejemplo:

gitlab/gitlab-ce:19.x.x-ce.0

16.2. Detener los servicios que escriben en la base de datos

docker exec -it gitlab gitlab-ctl stop puma
docker exec -it gitlab gitlab-ctl stop sidekiq

16.3. Consultar las copias disponibles

ls -lh /srv/gitlab/data/backups

Supongamos que existe:

1750000000_2026_07_20_19.x.x_gitlab_backup.tar

El identificador de la copia sería:

1750000000_2026_07_20_19.x.x

16.4. Ejecutar la restauración

docker exec -it gitlab \
gitlab-backup restore \
BACKUP=1750000000_2026_07_20_19.x.x

16.5. Reiniciar GitLab

docker restart gitlab

16.6. Comprobar la instalación

docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true

Fase 17. Actualización de GitLab

No debemos actualizar una instalación estable utilizando latest sin revisar previamente los cambios.

17.1. Consultar la imagen actual

docker inspect gitlab \
--format='{{.Config.Image}}'

17.2. Crear una copia

sudo /usr/local/sbin/copiar-gitlab.sh

17.3. Cambiar la versión

Editamos:

nano /srv/gitlab/.env

Cambiamos:

GITLAB_IMAGE=gitlab/gitlab-ce:VERSION-ce.0

17.4. Descargar y recrear el contenedor

cd /srv/gitlab
docker compose pull
docker compose up -d

17.5. Consultar los registros

docker compose logs -f gitlab

17.6. Comprobar el estado

docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true

GitLab recomienda crear una copia antes de actualizar. Para saltos grandes también puede exigir versiones intermedias obligatorias, por lo que no debe pasarse directamente de una versión muy antigua a la última sin revisar la ruta de actualización.


Fase 18. Firewall básico

18.1. Instalar UFW

sudo apt install -y ufw

18.2. Permitir SSH del servidor

Antes de activar el firewall:

sudo ufw allow OpenSSH

18.3. Permitir GitLab

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 2222/tcp

18.4. Activar el firewall

sudo ufw enable

18.5. Consultar las reglas

sudo ufw status numbered

Resultado esperado:

22/tcp    ALLOW
80/tcp    ALLOW
443/tcp   ALLOW
2222/tcp  ALLOW

Fase 19. Mantenimiento habitual

19.1. Consultar contenedores

docker ps

19.2. Consultar el espacio ocupado

docker system df
sudo du -sh /srv/gitlab/*

19.3. Consultar los registros recientes

docker compose logs --tail=100 gitlab

19.4. Reiniciar GitLab

cd /srv/gitlab
docker compose restart gitlab

19.5. Detener GitLab

docker compose stop

19.6. Iniciar GitLab

docker compose start

19.7. Recrear el contenedor

docker compose up -d

19.8. Comprobar internamente GitLab

docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true

19.9. Consultar el estado de sus componentes

docker exec -it gitlab gitlab-ctl status

Fase 20. Comprobaciones finales

Al terminar el proyecto deben cumplirse los siguientes puntos:

  • El servidor tiene una IP local fija.
  • El dominio apunta a la IP pública.
  • Los puertos 80, 443 y 2222 están redirigidos.
  • GitLab se abre mediante HTTPS.
  • El certificado es válido.
  • El registro público de usuarios está desactivado.
  • Los proyectos nuevos son privados.
  • Se ha creado un usuario personal.
  • La cuenta tiene autenticación de dos factores.
  • Cada ordenador dispone de su propia clave SSH.
  • Se puede clonar un repositorio.
  • Se pueden realizar pull, commit y push.
  • Un servidor externo puede clonar mediante una Deploy Key.
  • Existe un procedimiento de despliegue.
  • Se realizan copias automáticas.
  • Las copias se guardan fuera del disco principal.
  • Se conoce la versión exacta de GitLab.
  • Se ha probado al menos una restauración.

Resultado final

Al completar todas las fases tendremos una infraestructura personal parecida a esta:

                         INTERNET
                             │
                  gitlab.tudominio.es
                             │
                      HTTPS / SSH
                             │
                         ROUTER
                             │
                  ┌──────────┴──────────┐
                  │                     │
               80/443                 2222
                  │                     │
                  └──────────┬──────────┘
                             │
                    UBUNTU SERVER
                             │
                      DOCKER COMPOSE
                             │
                         GITLAB CE
                             │
       ┌─────────────────────┼─────────────────────┐
       │                     │                     │
   Repositorios          Copias             CI/CD futuro
       │
 ┌─────┼─────────┬───────────────┐
 │     │         │               │
PC   MacBook   Portátil      Servidor web

El servidor GitLab será el punto central de trabajo, pero cada equipo conservará también una copia local de los repositorios que utilice.

El flujo diario será:

git pull

Trabajar sobre el proyecto.

git add .
git commit -m "Descripción de los cambios"
git push

Y el flujo de despliegue inicial será:

cd /var/www/proyecto
git pull origin main

Posteriormente podrá sustituirse por un pipeline automático de GitLab CI/CD.