Add auto-deployment scripts for Gitea webhook
- deploy.sh: Script to pull code and restart Docker containers - webhook-server.py: HTTP server to receive Gitea push events - shorts-maker-webhook.service: Systemd service for webhook server - setup-autodeploy.sh: Setup script for the server 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
43
deploy.sh
Normal file
43
deploy.sh
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Auto-deployment script for shorts-maker
|
||||||
|
# This script is triggered by Gitea webhook on push
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
APP_DIR="/home/bini/shorts-maker"
|
||||||
|
LOG_FILE="/var/log/shorts-maker-deploy.log"
|
||||||
|
COMPOSE_FILE="docker-compose.yml"
|
||||||
|
|
||||||
|
# Logging function
|
||||||
|
log() {
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
log "=== Deployment started ==="
|
||||||
|
|
||||||
|
# Navigate to app directory
|
||||||
|
cd "$APP_DIR" || { log "ERROR: Cannot cd to $APP_DIR"; exit 1; }
|
||||||
|
|
||||||
|
# Pull latest code
|
||||||
|
log "Pulling latest code from git..."
|
||||||
|
git fetch origin
|
||||||
|
git reset --hard origin/main
|
||||||
|
log "Git pull completed"
|
||||||
|
|
||||||
|
# Rebuild and restart containers
|
||||||
|
log "Rebuilding Docker containers..."
|
||||||
|
docker compose -f "$COMPOSE_FILE" build --no-cache
|
||||||
|
|
||||||
|
log "Restarting containers..."
|
||||||
|
docker compose -f "$COMPOSE_FILE" down
|
||||||
|
docker compose -f "$COMPOSE_FILE" up -d
|
||||||
|
|
||||||
|
# Clean up old images
|
||||||
|
log "Cleaning up old Docker images..."
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
log "=== Deployment completed successfully ==="
|
||||||
|
|
||||||
|
# Show running containers
|
||||||
|
docker compose -f "$COMPOSE_FILE" ps
|
||||||
63
setup-autodeploy.sh
Normal file
63
setup-autodeploy.sh
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Setup script for auto-deployment on the server
|
||||||
|
# Run this script on the home server as root or with sudo
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
APP_DIR="/home/bini/shorts-maker"
|
||||||
|
SERVICE_NAME="shorts-maker-webhook"
|
||||||
|
|
||||||
|
echo "=== Shorts Maker Auto-Deploy Setup ==="
|
||||||
|
|
||||||
|
# 1. Make deploy script executable
|
||||||
|
echo "1. Setting up deploy script..."
|
||||||
|
chmod +x "$APP_DIR/deploy.sh"
|
||||||
|
chmod +x "$APP_DIR/webhook-server.py"
|
||||||
|
|
||||||
|
# 2. Create log files with proper permissions
|
||||||
|
echo "2. Creating log files..."
|
||||||
|
touch /var/log/shorts-maker-deploy.log
|
||||||
|
touch /var/log/webhook-server.log
|
||||||
|
chown bini:bini /var/log/shorts-maker-deploy.log
|
||||||
|
chown bini:bini /var/log/webhook-server.log
|
||||||
|
|
||||||
|
# 3. Generate webhook secret
|
||||||
|
WEBHOOK_SECRET=$(openssl rand -hex 32)
|
||||||
|
echo "3. Generated webhook secret: $WEBHOOK_SECRET"
|
||||||
|
echo " (Save this for Gitea webhook configuration!)"
|
||||||
|
|
||||||
|
# 4. Update systemd service with the secret
|
||||||
|
echo "4. Installing systemd service..."
|
||||||
|
sed "s/your-secret-here/$WEBHOOK_SECRET/" "$APP_DIR/shorts-maker-webhook.service" > /etc/systemd/system/$SERVICE_NAME.service
|
||||||
|
|
||||||
|
# 5. Reload and start service
|
||||||
|
echo "5. Starting webhook service..."
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable $SERVICE_NAME
|
||||||
|
systemctl start $SERVICE_NAME
|
||||||
|
|
||||||
|
# 6. Check status
|
||||||
|
echo ""
|
||||||
|
echo "=== Setup Complete ==="
|
||||||
|
echo ""
|
||||||
|
systemctl status $SERVICE_NAME --no-pager
|
||||||
|
echo ""
|
||||||
|
echo "=== Next Steps ==="
|
||||||
|
echo ""
|
||||||
|
echo "1. Configure Gitea webhook:"
|
||||||
|
echo " - Go to Repository Settings > Webhooks > Add Webhook"
|
||||||
|
echo " - Target URL: http://your-server-ip:9000/webhook"
|
||||||
|
echo " - HTTP Method: POST"
|
||||||
|
echo " - Content Type: application/json"
|
||||||
|
echo " - Secret: $WEBHOOK_SECRET"
|
||||||
|
echo " - Trigger: Push Events"
|
||||||
|
echo ""
|
||||||
|
echo "2. If using firewall, open port 9000:"
|
||||||
|
echo " sudo ufw allow 9000/tcp"
|
||||||
|
echo ""
|
||||||
|
echo "3. Test by pushing to main branch!"
|
||||||
|
echo ""
|
||||||
|
echo "=== Useful Commands ==="
|
||||||
|
echo "View logs: journalctl -u $SERVICE_NAME -f"
|
||||||
|
echo "Restart: sudo systemctl restart $SERVICE_NAME"
|
||||||
|
echo "Manual deploy: sudo -u bini $APP_DIR/deploy.sh"
|
||||||
21
shorts-maker-webhook.service
Normal file
21
shorts-maker-webhook.service
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Shorts Maker Webhook Server
|
||||||
|
After=network.target docker.service
|
||||||
|
Wants=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=bini
|
||||||
|
Group=bini
|
||||||
|
WorkingDirectory=/home/bini/shorts-maker
|
||||||
|
Environment=WEBHOOK_SECRET=your-secret-here
|
||||||
|
ExecStart=/usr/bin/python3 /home/bini/shorts-maker/webhook-server.py
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
StandardOutput=append:/var/log/webhook-server.log
|
||||||
|
StandardError=append:/var/log/webhook-server.log
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
131
webhook-server.py
Normal file
131
webhook-server.py
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Simple webhook server for Gitea auto-deployment.
|
||||||
|
Listens for push events and triggers deploy.sh
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import hmac
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
WEBHOOK_SECRET = os.environ.get('WEBHOOK_SECRET', 'your-secret-here')
|
||||||
|
DEPLOY_SCRIPT = '/home/bini/shorts-maker/deploy.sh'
|
||||||
|
PORT = 9000
|
||||||
|
LOG_FILE = '/var/log/webhook-server.log'
|
||||||
|
|
||||||
|
def log(message):
|
||||||
|
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
log_line = f"[{timestamp}] {message}"
|
||||||
|
print(log_line)
|
||||||
|
try:
|
||||||
|
with open(LOG_FILE, 'a') as f:
|
||||||
|
f.write(log_line + '\n')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def verify_signature(payload, signature):
|
||||||
|
"""Verify Gitea webhook signature"""
|
||||||
|
if not signature:
|
||||||
|
return False
|
||||||
|
expected = hmac.new(
|
||||||
|
WEBHOOK_SECRET.encode(),
|
||||||
|
payload,
|
||||||
|
hashlib.sha256
|
||||||
|
).hexdigest()
|
||||||
|
return hmac.compare_digest(f"sha256={expected}", signature)
|
||||||
|
|
||||||
|
class WebhookHandler(BaseHTTPRequestHandler):
|
||||||
|
def do_POST(self):
|
||||||
|
if self.path != '/webhook':
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
|
content_length = int(self.headers.get('Content-Length', 0))
|
||||||
|
payload = self.rfile.read(content_length)
|
||||||
|
|
||||||
|
# Verify signature if secret is configured
|
||||||
|
if WEBHOOK_SECRET != 'your-secret-here':
|
||||||
|
signature = self.headers.get('X-Gitea-Signature')
|
||||||
|
if not verify_signature(payload, signature):
|
||||||
|
log("ERROR: Invalid webhook signature")
|
||||||
|
self.send_response(403)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b'Invalid signature')
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = json.loads(payload)
|
||||||
|
ref = data.get('ref', '')
|
||||||
|
|
||||||
|
# Only deploy on push to main branch
|
||||||
|
if ref == 'refs/heads/main':
|
||||||
|
log(f"Received push to main from {data.get('pusher', {}).get('name', 'unknown')}")
|
||||||
|
log(f"Commit: {data.get('after', 'unknown')[:8]}")
|
||||||
|
|
||||||
|
# Run deploy script
|
||||||
|
log("Starting deployment...")
|
||||||
|
result = subprocess.run(
|
||||||
|
['bash', DEPLOY_SCRIPT],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=600 # 10 minute timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
log("Deployment successful!")
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b'Deployment successful')
|
||||||
|
else:
|
||||||
|
log(f"Deployment failed: {result.stderr}")
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(f'Deployment failed: {result.stderr}'.encode())
|
||||||
|
else:
|
||||||
|
log(f"Ignoring push to {ref}")
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b'Ignored (not main branch)')
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
log("ERROR: Invalid JSON payload")
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b'Invalid JSON')
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
log("ERROR: Deployment timed out")
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b'Deployment timed out')
|
||||||
|
except Exception as e:
|
||||||
|
log(f"ERROR: {str(e)}")
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(f'Error: {str(e)}'.encode())
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path == '/health':
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b'OK')
|
||||||
|
else:
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
log(f"HTTP: {args[0]}")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
log(f"Starting webhook server on port {PORT}")
|
||||||
|
server = HTTPServer(('0.0.0.0', PORT), WebhookHandler)
|
||||||
|
try:
|
||||||
|
server.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
log("Shutting down webhook server")
|
||||||
|
server.shutdown()
|
||||||
Reference in New Issue
Block a user