El SECRETO de los SysAdmins PRO: Gestiona Servidores con Git y Gitea
Aprenderás a dejar de tocar producción a pelo y a montar tu puesto de mando con Git para configs y scripts: una fuente de verdad con historial, auditoría (git log/blame), ramas y reversión real. Verás casos prácticos (Nginx/Apache y scripts “final_final”), entenderás las dos vertientes (Git como histórico vs Git como origen de despliegue) y, en este guion, te centrarás en la primera mientras montas un servidor Git local con Gitea para tenerlo bajo tu control.
Este glosario pone orden a las ideas clave de “llevar producción con cabeza usando Git”: desde frenar la deriva de configuración y ganar trazabilidad, hasta trabajar con repos, commits, ramas y un servidor Git como Gitea para tener una única fuente de verdad y un “deshacer” real.
- Git
- Es el sistema que convierte todo lo de texto —configs, scripts y notas— en algo versionado, con historia y retroceso seguro. En tu día a día lo notarás cuando dejes de tocar en caliente por SSH y pases a cambiar en local, probar y subir el cambio con calma, sabiendo que puedes volver atrás si sale rana.
- Repositorio (repo) Git
- Es la “carpeta con superpoderes” donde viven tus ficheros y su historial. Verás repos como server-configs/nginx o apache: clonas, trabajas, haces commits y empujas al servidor. El repo sustituye a la selva de “config copia 2” y te da una historia clara de qué cambió y por qué.
- Commit
- Es una foto coherente de tus cambios con un mensaje que cuenta el motivo. En el curro, escribir “aumentar límite de subida a 25M” vale oro: dentro de un mes sabrás qué tocaste y por qué, y podrás comparar línea a línea sin adivinar.
- Hash (integridad del historial)
- Cada commit lleva un identificador calculado que delata cualquier manipulación. En la práctica significa que el historial es confiable: si alguien cambia algo a escondidas, Git lo canta; si no, puedes reconstruir el estado exacto de hace veinte minutos sin truquitos.
- Trazabilidad
- Es poder responder quién tocó qué, cuándo y con qué mensaje. Te salva cuando producción se cae después de “un cambio tonto”: abres el repo, miras los últimos commits y dejas de jugar al CSI para pasar a arreglar con datos.
git log- El timeline de tu proyecto: autor, fecha y mensaje de cada cambio. Es lo primero que mirarás cuando algo se tuerza; te da el hilo para entender el contexto antes de decidir si revertir, corregir o seguir adelante.
git blame- Te dice, línea a línea, quién fue la última persona que tocó cada parte. No va de señalar: va de encontrar rápido a quien sabe por qué está eso así y recuperar el contexto sin perder una hora leyendo todo el repo.
- Ramas (branches)
- Son copias de trabajo aisladas para experimentar sin romper la principal. En el día a día creas una rama, pruebas la configuración o el script en laboratorio, y si convence, lo integras; si no, borras la rama y aquí paz y después gloria.
- Deriva de configuración
- Es cuando cada servidor tiene “su historia” porque fuiste tocando a mano con prisas. La reconocerás por carpetas con config_old y ajustes misteriosos “que funcionan”. Con Git, esa deriva se corta porque toda modificación pasa por un commit trazado.
- Fuente única de verdad (SSOT)
- Es decidir que lo que está en Git es lo real y todo se despliega desde ahí. En el día a día evita discusiones y sustos: si algo difiere en el servidor, no se toca a mano; se arregla en el repo, se documenta y se despliega igual para todos.
- Rollback en Git
- Es volver a un estado bueno conocido sin dramas. Después de una regla de cortafuegos que te deja fuera, tiras del commit anterior y recuperas servicio sin rezar a los dioses de “config copia FINAL de verdad”.
- Despliegue seguro (validar y recargar)
- Es aplicar cambios con un script que trae del repo, comprueba sintaxis y solo recarga si pasa la prueba. En tu rutina con Nginx o Apache, esto significa cero recargas a ciegas y menos sustos en producción.
- Antipatrón “.bak en el mismo disco”
- Renombrar el fichero a .bak en el propio servidor parece plan, pero cae con el mismo susto, no tiene verificación y no deja historia. Al migrar a Git, este hábito desaparece porque el “backup” es el historial completo y verificable.
- Servidor Git
- Es el punto central al que empujas y desde el que sincronizas. En tu día a día te da colaboración de verdad, permisos por proyecto, copias seguras y el sitio al que apuntan tus scripts de despliegue.
- Gitea
- Es un servidor Git ligero y fácil de montar en tu propia infraestructura. Lo verás como tu “GitHub interno”: repos privados, usuarios, revisiones y una interfaz cómoda para que el equipo deje de pasar zips por chat y empiece a trabajar con procesos.
- Configuración como código (CaC)
- Tratar configs y scripts como software: versionados, revisados y desplegados desde Git. En el día a día cambia el juego: de “entro por SSH un segundo” a “abro una rama, hago commit con mensaje claro, valido y despliego con control”.

Instalar Gitea en Ubuntu Server 24.04 (binario nightly 1.25) como servicio systemd
Guía corta y directa para dejar Gitea funcionando como servicio en Ubuntu 24.04. Usaremos el binario nightly 1.25, usuario de servicio git, datos en /var/lib/gitea y configuración en /etc/gitea. Si es producción, valora usar una versión estable.
URL de descarga solicitada: https://dl.gitea.com/gitea/1.25-nightly/gitea-1.25-nightly-linux-amd64
1) Requisitos
- Ubuntu Server 24.04 con
sudo. - Puerto 3000/TCP libre (por defecto) para Gitea.
- Editor al gusto (
nano/vi). - Usaremos MariaDB (puedes adaptar a PostgreSQL o SQLite si lo prefieres).
Nota: Un nightly es para pruebas. En producción, usa versión estable y valida checksums/firmas.
2) Preparación del sistema
sudo apt update && sudo apt upgrade -y sudo apt install -y git curl ca-certificates tar ufw mariadb-server mariadb-client
3) Crear usuario de servicio
sudo adduser --system --shell /bin/bash --gecos 'Gitea Service' --group --disabled-password --home /home/git git id git getent passwd git
4) Instalar el binario nightly
Colocaremos el binario en /usr/local/bin/gitea. Si tu /usr/local está montado con noexec, usa /usr/bin.
sudo systemctl stop gitea 2>/dev/null || true sudo rm -f /usr/local/bin/gitea /usr/bin/gitea sudo curl -L "https://dl.gitea.com/gitea/1.25-nightly/gitea-1.25-nightly-linux-amd64" -o /usr/local/bin/gitea sudo chown root:root /usr/local/bin/gitea sudo chmod 0755 /usr/local/bin/gitea
4.1 Verificaciones rápidas
file /usr/local/bin/gitea head -c 4 /usr/local/bin/gitea | hexdump -C /usr/local/bin/gitea --version sudo -u git /usr/local/bin/gitea --version
Debe ser un ejecutable ELF x86-64. Si ves Mach-O o HTML text, revisa la URL y descarga con -L.
5) Carpetas y permisos
Estructura recomendada (datos/logs en /var/lib/gitea y configuración en /etc/gitea):
#!/usr/bin/env bash
set -euo pipefail
GITEA_USER=git
GITEA_GROUP=git
GITEA_WORKDIR=/var/lib/gitea
GITEA_ETC=/etc/gitea
APP_INI=${GITEA_ETC}/app.ini
SYSTEMD_DROP_DIR=/etc/systemd/system/gitea.service.d
OVERRIDE_FILE=${SYSTEMD_DROP_DIR}/override.conf
OVERRIDE_CONTENT=$'[Service]\nReadWritePaths=/etc/gitea\n'
sudo systemctl stop gitea.service 2>/dev/null || true
# Datos y logs (git:git, 750)
sudo install -d -o "${GITEA_USER}" -g "${GITEA_GROUP}" -m 0750 "${GITEA_WORKDIR}/custom" "${GITEA_WORKDIR}/data" "${GITEA_WORKDIR}/log"
# /etc/gitea (root:git 770)
sudo install -d -o root -g "${GITEA_GROUP}" -m 0770 "${GITEA_ETC}"
# app.ini (root:git 660)
if [ ! -f "${APP_INI}" ]; then
sudo install -m 0660 /dev/null "${APP_INI}"
sudo chown root:"${GITEA_GROUP}" "${APP_INI}"
else
sudo chown root:"${GITEA_GROUP}" "${APP_INI}"
sudo chmod 0660 "${APP_INI}"
fi
# Drop-in systemd para permitir /etc/gitea en escritura
sudo mkdir -p "${SYSTEMD_DROP_DIR}"
printf "%s" "${OVERRIDE_CONTENT}" | sudo tee "${OVERRIDE_FILE}" >/dev/null
sudo systemctl daemon-reload
6) Base de datos (MariaDB)
sudo systemctl enable --now mariadb sudo mysql_secure_installation
Crear base de datos y usuario (ajusta la contraseña):
sudo mysql -u root -p <<'SQL' CREATE DATABASE giteadb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'gitea'@'localhost' IDENTIFIED BY 'CambiaEstaPassword!'; GRANT ALL PRIVILEGES ON giteadb.* TO 'gitea'@'localhost'; FLUSH PRIVILEGES; SQL
7) Servicio systemd
Crea la unidad en /etc/systemd/system/gitea.service:
[Unit] Description=Gitea (Git with a cup of tea) After=network-online.target Wants=network-online.target [Service] Type=simple User=git Group=git WorkingDirectory=/var/lib/gitea Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini Restart=always RestartSec=2s LimitNOFILE=1048576 TimeoutStopSec=20s # Endurecimiento básico PrivateTmp=true ProtectSystem=full ReadWritePaths=/etc/gitea ProtectHome=true NoNewPrivileges=true [Install] WantedBy=multi-user.target
Aplica y arranca:
sudo systemctl daemon-reload sudo systemctl enable gitea sudo systemctl start gitea systemctl status gitea --no-pager journalctl -u gitea -n 50 --no-pager -q
8) Firewall y acceso inicial
sudo ufw allow OpenSSH sudo ufw allow 3000/tcp sudo ufw enable sudo ufw status
Abre en el navegador: http://IP_DEL_SERVIDOR:3000/ y completa el asistente con estos valores recomendados:
- Database: MySQL/MariaDB
- Host:
127.0.0.1:3306 - Name:
giteadb - User:
gitea - Password: (la que has puesto)
- Application URL:
http://IP:3000/o tu dominio - Repository Root Path:
/var/lib/gitea/data/gitea-repositories - LFS Root Path:
/var/lib/gitea/data/lfs - Log Path:
/var/lib/gitea/log - Run As:
git - Config File:
/etc/gitea/app.ini
9) (Opcional) Proxy inverso con Nginx + TLS
sudo apt install -y nginx
sudo tee /etc/nginx/sites-available/gitea >/dev/null <<'NGINX'
server {
listen 80;
server_name gitea.example.com;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:3000;
}
}
NGINX
sudo ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/gitea
sudo nginx -t && sudo systemctl reload nginx
Certificado TLS con Let's Encrypt:
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d gitea.example.com
Ajusta ROOT_URL y escucha local en app.ini si usas proxy:
ROOT_URL = https://gitea.example.com/ PROTOCOL = http HTTP_ADDR = 127.0.0.1
10) Copias de seguridad
- Datos:
/var/lib/gitea - Config:
/etc/gitea/app.ini - Base de datos:
mysqldump -u root -p giteadb > /root/backup-gitea-$(date +%F).sql
11) Actualizar el binario
Descarga el nuevo binario, valida y sustituye de forma atómica:
sudo systemctl stop gitea sudo install -m 0755 -o root -g root /usr/local/bin/gitea.new /usr/local/bin/gitea sudo systemctl start gitea
12) Problemas comunes
status=203/EXEC: binario inválido o /usr/local con noexec. Pon el binario en /usr/bin y ajusta ExecStart.
permission denied en datos/logs: revisa propietarios (git:git) y permisos (750).
Proxy sin estáticos: revisa ROOT_URL y cabeceras de Nginx.
13) Ejemplo mínimo de app.ini
[server] APP_NAME = Gitea PROTOCOL = http DOMAIN = 127.0.0.1 HTTP_ADDR = 0.0.0.0 HTTP_PORT = 3000 ROOT_URL = http://127.0.0.1:3000/ DISABLE_SSH = false START_SSH_SERVER = false LFS_START_SERVER = true LFS_CONTENT_PATH = /var/lib/gitea/data/lfs [database] DB_TYPE = mysql HOST = 127.0.0.1:3306 NAME = giteadb USER = gitea PASSWD = CambiaEstaPassword! SSL_MODE = disable [paths] APP_DATA_PATH = /var/lib/gitea [log] MODE = file LEVEL = info ROOT_PATH = /var/lib/gitea/log
14) Checklist final
file /usr/local/bin/gitea→ ejecutable ELF x86-64sudo -u git /usr/local/bin/gitea --version→ muestra versiónsystemctl is-enabled gitea→ enabledsystemctl status gitea→ active (running)ss -ltnp | grep :3000→ escucha en 0.0.0.0:3000 o 127.0.0.1:3000- Asistente web completado y usuario admin creado
Próximamente contenido premium
De esto trata el Vídeo
Durante años fui el típico “bombero” de sistemas: diez sesiones SSH abiertas, cambios rápidos “solo para probar” y esa sensación constante de estar jugando a la ruleta rusa con producción. Seguro que te suena. Copias con nombres imposibles tipo config_final_de_verdad o scripts llamados backup_final_v3.sh. Todo funcionaba… hasta que dejaba de hacerlo.
Y es que ese caos no viene de falta de profesionalidad, sino de no tener una fuente de verdad única. Sin trazabilidad ni control, cada cambio manual en el servidor es tirar los dados. Un error en un «:wq» y adiós.
La solución no es mágica, pero sí muy poderosa: traer Git a nuestro día a día. No como una moda, sino como una red de seguridad para todo lo que es texto: configuraciones, scripts, documentación. Con Git, cada cambio tiene su historia, cada error se puede deshacer y cada línea tiene nombre y apellido.
Además, Git nos da libertad para experimentar sin miedo. Podemos crear ramas, probar ideas, romper cosas y volver atrás en segundos. Y si trabajas con servidores web o scripts, mantener un repositorio organizado cambia el juego por completo: adiós a los “config copia” y hola a la trazabilidad real.
En este capítulo me centro en lo primero: usar Git como histórico de copias bien organizado. Y para eso, te enseño cómo montar tu propio servidor Git local con Gitea, una opción ligera, sencilla y perfecta para mantener el control total sobre tu infraestructura.

