Add deployment workflow (docker-compose, deploy.sh, webhook receiver)

This commit is contained in:
2026-06-10 11:17:08 +02:00
parent 84c933ea9c
commit b9fc741505
5 changed files with 129 additions and 11 deletions
+3 -11
View File
@@ -1,11 +1,3 @@
# AufmaßWeb Konfiguration DATABASE_URL=postgresql://aufmass:aufmass_secret@localhost:5432/aufmassweb
# Kopiere diese Datei nach .env und passe die Werte an SECRET_KEY=change-me-in-production
REGISTRATION_ENABLED=false
SECRET_KEY=ersetzen-mit-sicherem-schluessel-mindestens-32-zeichen
# SQLite (Entwicklung lokal):
# DATABASE_URL=sqlite:///data/aufmass.db
# PostgreSQL (Produktion / Docker):
DATABASE_URL=postgresql://user:password@host:5432/aufmassweb
FLASK_ENV=production
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
set -e
REPO_DIR="/opt/aufmassweb"
COMPOSE_FILE="docker-compose.deploy.yml"
LOG_FILE="/var/log/aufmassweb-deploy.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
log "=== Deployment gestartet ==="
cd "$REPO_DIR"
log "Pull von Gitea..."
git pull origin main 2>&1 | tee -a "$LOG_FILE"
log "Docker Compose build..."
docker compose -f "$COMPOSE_FILE" build 2>&1 | tee -a "$LOG_FILE"
log "Docker Compose up (Rolling-Restart)..."
docker compose -f "$COMPOSE_FILE" up -d --remove-orphans 2>&1 | tee -a "$LOG_FILE"
log "Alte Images bereinigen..."
docker image prune -f 2>&1 | tee -a "$LOG_FILE"
log "=== Deployment erfolgreich abgeschlossen ==="
+34
View File
@@ -0,0 +1,34 @@
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: aufmassweb
POSTGRES_USER: aufmass
POSTGRES_PASSWORD: ${DB_PASSWORD:-aufmass_secret}
healthcheck:
test: ["CMD", "pg_isready", "-U", "aufmass", "-d", "aufmassweb"]
interval: 10s
timeout: 5s
retries: 5
web:
build: ./_aufmass_web
restart: unless-stopped
ports:
- "5000:5000"
volumes:
- ./_aufmass_web/data:/app/data
- ./daten:/app/daten
environment:
DATABASE_URL: postgresql://aufmass:${DB_PASSWORD:-aufmass_secret}@postgres:5432/aufmassweb
SECRET_KEY: ${SECRET_KEY:-change-me-in-production}
REGISTRATION_ENABLED: "false"
depends_on:
postgres:
condition: service_healthy
volumes:
pgdata:
+48
View File
@@ -0,0 +1,48 @@
import os
import subprocess
import hmac
import hashlib
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = os.environ.get("WEBHOOK_SECRET", "change-me")
DEPLOY_SCRIPT = os.environ.get("DEPLOY_SCRIPT", "/opt/aufmassweb/deploy.sh")
def verify_signature(payload, signature):
if not signature:
return False
expected = "sha256=" + hmac.new(WEBHOOK_SECRET.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
@app.route("/webhook", methods=["POST"])
def webhook():
signature = request.headers.get("X-Gitea-Signature", "")
payload = request.get_data()
if not verify_signature(payload, signature):
return jsonify({"error": "invalid signature"}), 403
data = request.get_json(silent=True) or {}
ref = data.get("ref", "")
if ref != "refs/heads/main":
return jsonify({"message": f"ignored push to {ref}"}), 200
result = subprocess.run(
["bash", DEPLOY_SCRIPT],
capture_output=True, text=True, timeout=300
)
return jsonify({
"status": "ok" if result.returncode == 0 else "error",
"stdout": result.stdout,
"stderr": result.stderr,
}), (200 if result.returncode == 0 else 500)
@app.route("/health", methods=["GET"])
def health():
return jsonify({"status": "ok"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5001)
+16
View File
@@ -0,0 +1,16 @@
[Unit]
Description=Webhook Receiver für AufmaßWeb Deployment
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/aufmassweb
ExecStart=/usr/bin/python3 /opt/aufmassweb/webhook_deploy.py
Restart=always
RestartSec=5
Environment=WEBHOOK_SECRET=change-me
Environment=DEPLOY_SCRIPT=/opt/aufmassweb/deploy.sh
[Install]
WantedBy=multi-user.target