Introducción
Me parece una excelente práctica tener todos mis proyectos y trabajos respaldados en un servidor remoto. Para mis proyectos personales generalmente uso GitHub, dejando los repositorios abiertos a la comunidad. Sin embargo, no quiero mezclar mis proyectos personales y Open Source con aquellos que corresponden a servicios que ofrezco a otros. Para este segundo caso, la mejor solución es usar mi propio servidor como servidor Git, haciendo los push directamente allí. Las ventajas que esto me ofrece son: una mayor autoridad sobre mis propios datos, un control de acceso personalizado por si en el futuro quiero colaborar, y una mayor personalización.
Repositorios Bare
Un repositorio bare es un repositorio Git sin working tree: no contiene una copia extraída de los archivos del proyecto, sino únicamente la base de datos de objetos y referencias que en un repositorio normal se encuentra dentro de .git/. En lugar de anidarse en un subdirectorio .git, ese contenido ocupa directamente la raíz del repositorio. Por convención, el nombre del directorio termina en .git (por ejemplo mi-proyecto.git), lo cual no es obligatorio pero sí el estándar. Un repositorio remoto que recibe push y pull debe ser bare.
Configurar Servidor Git
Primero es importante tener en cuenta que Git permite conectarse sin credenciales usando el protocolo git://, que usa el puerto 9418 por defecto. De esta manera cualquier usuario podría clonar los repositorios sin restricciones. Para el uso que yo le voy a dar no usaré nunca el protocolo git://, sino que en cambio usaré Git sobre ssh, que viene habilitado por defecto. Usando ssh no se necesita tener ningún daemon ejecutándose en segundo plano, ya que los comandos se ejecutan en el servidor vía ssh usando git-shell como intérprete, que es mucho más seguro que bash. Git también permite escuchar a través del protocolo https:// con credenciales, pero usar ssh resulta mucho más sencillo, por lo cual descartaré esa opción.
-
Crear el usuario dedicado para Git. El hecho de que sea un usuario dedicado lo hace mucho más seguro. Además, al usar
git-shellcomo intérprete en lugar debash, no puede usarse para administrar el servidor remotamente.sudo useradd -m -s /usr/bin/git-shell git -
Crear la carpeta para las claves SSH y el archivo
authorized_keys. Es importante queauthorized_keysexista como archivo antes de añadir claves, de lo contrario algunos sistemas lo crearán como directorio y la autenticación no funcionará.mkdir /home/git/.ssh chmod 700 /home/git/.ssh touch /home/git/.ssh/authorized_keys chmod 600 /home/git/.ssh/authorized_keys -
Cambiar el propietario de
/home/git/para añadir una capa extra de seguridad, y crear la carpetarepos.sudo chown root:root /home/git sudo chmod 711 /home/git sudo mkdir /home/git/repos sudo chown git:git /home/git/repos -
Deshabilitar la autenticación por contraseña y habilitar la autenticación por clave pública editando
/etc/ssh/sshd_config:PasswordAuthentication no PubkeyAuthentication yesY reiniciar el servicio:
sudo systemctl restart sshd -
Añadir las claves públicas de los usuarios autorizados al archivo
authorized_keys:cat ~/.ssh/id_ed25519.pub >> /home/git/.ssh/authorized_keys(Nota: tener en cuenta que para copiar las claves puede ser necesario usar ssh desde el cliente al servidor)
A partir de aquí ya es posible crear repositorios bare y hacer push directamente al servidor:
git init --bare /home/git/repos/mi-proyecto.git
Nota: Es recomendable usar
git config --system init.defaultBranch mainantes de iniciar repositorios bare para que el HEAD apunte amainy no amaster. En caso de no agregar esta configuración, al clonar el repositorio aparecerá un mensajeRemote branch 'HEAD' not found in upstream origin
Y desde el cliente:
git remote add origin ssh://git@mi-servidor/home/git/repos/mi-proyecto.git
git push -u origin main
Git-Shell
git-shell es un shell de inicio de sesión restringido que actúa como filtro entre sshd y los programas de transporte de Git: valida el comando solicitado por el cliente y, si está permitido, lo sustituye mediante exec por git-receive-pack, git-upload-pack o git-upload-archive, que son los que implementan el protocolo con el cliente.
Sin embargo, si se crea el directorio ~/git-shell-commands, es posible conectarse a la shell en modo interactivo. En ese modo, git-shell muestra un prompt git> desde el que solo pueden ejecutarse los ejecutables contenidos en ese directorio, además de los built-ins exit, quit, logout y bye. Si existe git-shell-commands/help, se ejecuta automáticamente al iniciar la sesión, y el usuario puede volver a invocarlo con help.
Git-shell-commands
Descripción
Los git-shell-commands son scripts ejecutables que extienden las capacidades de git-shell. Cuando un usuario se conecta vía SSH al servidor, git-shell actúa como intérprete restringido — solo permite operaciones git y los comandos personalizados que se hayan definido.
Comandos Built-in
Por defecto git-shell únicamente permite las operaciones básicas de git: clonar, hacer push y pull. Cualquier intento de ejecutar otros comandos es rechazado. Esto lo hace ideal para un servidor git dedicado, ya que el usuario no puede usar la conexión SSH para administrar el servidor.
Crear Personalizados
Se pueden crear comandos personalizados, creando scritps en el directorio ~/git-shell-commands/ del usuario git. Cada script se convierte en un comando disponible vía SSH:
ssh git@servidor nuevo-comando
Los scripts pueden estar escritos en cualquier lenguaje disponible en el servidor, aunque lo más habitual es usar bash o sh. Por ejemplo, el comando new que crea un repositorio bare:
#!/bin/sh
if [ -z "$1" ]; then
echo "Usage: new <repo-name>"
exit 1
fi
git init --bare /home/git/repos/$1.git
echo "Repo $1 created."
Servidor Git en Docker
Prefiero alojar el servidor Git dentro de un contenedor Docker, tanto por seguridad como por portabilidad. Para eso creé una imagen personalizada basada en Alpine Linux junto con un docker-compose que gestiona su configuración. La imagen incluye comandos de gestión de repositorios accesibles vía ssh (new, list, delete, etc.), datos persistentes mediante bind mounts, soporte para agregar claves ssh sin reiniciar el contenedor, y arranque automático con el sistema.
Está disponible en el siguiente repositorio:
https://github.com/maagenta/git-server-docker/tree/main