El problema#
Tengo tres servidores en casa y llega un momento donde necesitas cambios consistentes en todos. Actualizar servicios manualmente en cada máquina es tedioso y propenso a errores. Necesitaba una solución que sincronizara automáticamente mis docker-compose.yml sin intervención manual.
La solución: Git + Webhooks#
Mi enfoque es simple: usar un repositorio Git como fuente de verdad y webhooks para triggear actualizaciones automáticas en cada servidor cuando hago push a main.
Setup en el servidor central (repositorio)#
Primero, creé un repositorio Git bare en mi servidor principal. Lo uso como “servidor central” aunque técnicamente solo es un repositorio.
ssh user@servidor-principal
mkdir -p /opt/repos/docker-configs.git
cd /opt/repos/docker-configs.git
git init --bareEn mi máquina local clono y agrego mis configuraciones:
git clone ssh://user@servidor-principal/opt/repos/docker-configs.git
cd docker-configs
# Aquí agrego mis docker-compose.yml de los serviciosWebhooks con Gitea (opcional pero recomendado)#
Instalé Gitea en mi servidor principal para manejar webhooks de forma más elegante. No es obligatorio, pero simplifica la administración.
Si usas Gitea, configura un webhook POST en cada repositorio que apunte a cada servidor. La URL será algo como:
http://servidor-secundario:9000/webhook/deployScript de deploy en cada servidor#
En cada servidor (incluyendo el principal) creé un script que recibe el webhook y actualiza los servicios:
#!/bin/bash
# /opt/scripts/deploy-webhook.sh
REPO_PATH="/opt/docker-configs"
WEBHOOK_SECRET="tu-secreto-aqui"
# Validar secret (opcional pero recomendado)
if [ "$1" != "$WEBHOOK_SECRET" ]; then
echo "Secret inválido"
exit 1
fi
cd $REPO_PATH
git fetch origin main
git reset --hard origin/main
# Reiniciar servicios afectados
docker-compose -f docker-compose.yml up -d
echo "Deploy completado: $(date)" >> /var/log/docker-deploy.logDale permisos de ejecución:
chmod +x /opt/scripts/deploy-webhook.shServidor web simple para recibir webhooks#
Instalé un microservidor HTTP minimalista. Uso Python para no depender de cosas pesadas:
#!/usr/bin/env python3
# /opt/scripts/webhook-server.py
from http.server import HTTPServer, BaseHTTPRequestHandler
import subprocess
import json
class WebhookHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
# Ejecutar script de deploy
subprocess.run(['/opt/scripts/deploy-webhook.sh', 'tu-secreto-aqui'])
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({"status": "ok"}).encode())
if __name__ == '__main__':
server = HTTPServer(('0.0.0.0', 9000), WebhookHandler)
print('Webhook server listening on port 9000')
server.serve_forever()Ejecútalo con systemd para que persista:
[Unit]
Description=Docker Deploy Webhook
After=network.target
[Service]
Type=simple
User=docker
ExecStart=/usr/bin/python3 /opt/scripts/webhook-server.py
Restart=always
[Install]
WantedBy=multi-user.targetConfigurar en Gitea#
En la interfaz de Gitea, agrega un webhook POST para cada servidor con:
- URL del payload:
http://servidor-secundario:9000/webhook - Eventos: Push events
- Secret: tu-secreto-aqui (la misma que en el script)
Flujo de trabajo#
Ahora mi workflow es:
# En mi máquina local
cd docker-configs
# Editar archivos
vim docker-compose.yml
git add .
git commit -m "Agregar nuevo servicio nginx"
git push origin mainEn cuestión de segundos, todos mis servidores reciben el webhook, actualizan el repositorio y reinician los servicios.
Ventajas reales#
- Versionado: Todo está en Git. Puedo ver quién cambió qué y cuándo
- Rollback fácil: Si algo explota,
git reverty push - Auditoria: Logs de deploy automáticos
- Sin SSH manual: No necesito conectarme a cada servidor
Lo que aprendí#
El mayor error que cometí fue no validar el secreto del webhook. Cualquiera en mi red podía triggerear deploys. Ahora siempre valido.
También descubrí que es importante que el usuario que ejecuta el script tenga permisos suficientes con Docker. Usa usermod -aG docker usuario en cada servidor.
Esta setup funciona bien para tres servidores. Si escalaras a más, probablemente querría considerar herramientas como Ansible o K3s, pero para infraestructura casera es limpio y funcional.