Add Gitea Actions workflow for auto-deployment
Some checks failed
Deploy to Server / deploy (push) Has been cancelled

Replace webhook-based deployment with Gitea Actions workflow.
On push to main, the workflow will:
- SSH into the server
- Pull latest code
- Rebuild and restart Docker containers

Required secrets in Gitea:
- SERVER_HOST
- SERVER_USER
- SERVER_SSH_KEY
- SERVER_PORT

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kihong.kim
2026-01-04 19:06:52 +09:00
parent 3488d5118f
commit 40d7512e44
5 changed files with 40 additions and 215 deletions

View File

@@ -0,0 +1,40 @@
name: Deploy to Server
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to server via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
port: ${{ secrets.SERVER_PORT }}
script: |
cd /home/bini/shorts-maker
echo "=== Pulling latest code ==="
git fetch origin
git reset --hard origin/main
echo "=== Rebuilding Docker containers ==="
docker compose build --no-cache
echo "=== Restarting containers ==="
docker compose down
docker compose up -d
echo "=== Cleaning up old images ==="
docker image prune -f
echo "=== Deployment completed ==="
docker compose ps

View File

@@ -1,63 +0,0 @@
#!/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"

View File

@@ -1,21 +0,0 @@
[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

View File

@@ -1,131 +0,0 @@
#!/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()