pounce/.gitea/workflows/deploy.yml
Workflow config file is invalid. Please check your config file: yaml: line 66: could not find expected ':'
Yves Gugger d170d6f729 ci: Auto-deploy on push via SSH
- Gitea Actions workflow now syncs repo to server, builds images, restarts containers, and runs health checks
- Removed all hardcoded secrets from scripts/deploy.sh
- Added CI/CD documentation and ignored .env.deploy

NOTE: Existing secrets previously committed must be rotated.
2025-12-21 15:23:04 +01:00

195 lines
7.1 KiB
YAML

name: Deploy Pounce (Auto)
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install deploy tooling
run: |
apt-get update
apt-get install -y --no-install-recommends openssh-client rsync ca-certificates
- name: Setup SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H "${{ secrets.DEPLOY_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null
- name: Sync repository to server
run: |
rsync -az --delete \
-e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=yes" \
--exclude ".git" \
--exclude "frontend/node_modules" \
--exclude "frontend/.next" \
--exclude "**/__pycache__" \
--exclude "**/*.pyc" \
./ \
"${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:${{ secrets.DEPLOY_PATH }}/"
- name: Deploy (build + restart + health check)
env:
DEPLOY_SUDO_PASSWORD: ${{ secrets.DEPLOY_SUDO_PASSWORD }}
# App secrets (used to generate backend env file on server)
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
GH_OAUTH_SECRET: ${{ secrets.GH_OAUTH_SECRET }}
CZDS_USERNAME: ${{ secrets.CZDS_USERNAME }}
CZDS_PASSWORD: ${{ secrets.CZDS_PASSWORD }}
run: |
ssh -i ~/.ssh/deploy_key "${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}" << 'DEPLOY_EOF'
set -euo pipefail
# Use sudo non-interactively (password supplied via env)
sudo_cmd() {
printf '%s\n' "$DEPLOY_SUDO_PASSWORD" | sudo -S "$@"
}
# Ensure dirs
sudo_cmd mkdir -p /data/pounce/env /data/pounce/zones
sudo_cmd chmod -R 755 /data/pounce || true
# Generate backend env file from pipeline-provided secrets (never echo values)
sudo_cmd python3 - <<'PY'
import os
from pathlib import Path
env = {
# Core
"ENVIRONMENT": "production",
"ENABLE_SCHEDULER": "true",
"COOKIE_SECURE": "true",
"CORS_ORIGINS": "https://pounce.ch,https://www.pounce.ch",
"SITE_URL": "https://pounce.ch",
"FRONTEND_URL": "https://pounce.ch",
# Data dirs
"CZDS_DATA_DIR": "/data/czds",
"SWITCH_DATA_DIR": "/data/switch",
"ZONE_RETENTION_DAYS": "3",
# DB/Redis
"DATABASE_URL": os.environ["DATABASE_URL"],
"REDIS_URL": "redis://pounce-redis:6379/0",
# Auth
"SECRET_KEY": os.environ["SECRET_KEY"],
"JWT_SECRET": os.environ["SECRET_KEY"],
# SMTP
"SMTP_HOST": "smtp.zoho.eu",
"SMTP_PORT": "465",
"SMTP_USER": "hello@pounce.ch",
"SMTP_PASSWORD": os.environ["SMTP_PASSWORD"],
"SMTP_FROM_EMAIL": "hello@pounce.ch",
"SMTP_FROM_NAME": "pounce",
"SMTP_USE_TLS": "false",
"SMTP_USE_SSL": "true",
# Stripe
"STRIPE_SECRET_KEY": os.environ["STRIPE_SECRET_KEY"],
"STRIPE_PUBLISHABLE_KEY": "pk_live_51ScLbjCtFUamNRpNeFugrlTIYhszbo8GovSGiMnPwHpZX9p3SGtgG8iRHYRIlAtg9M9sl3mvT5r8pwXP3mOsPALG00Wk3j0wH4",
"STRIPE_PRICE_TRADER": "price_1ScRlzCtFUamNRpNQdMpMzxV",
"STRIPE_PRICE_TYCOON": "price_1SdwhSCtFUamNRpNEXTSuGUc",
"STRIPE_WEBHOOK_SECRET": os.environ["STRIPE_WEBHOOK_SECRET"],
# OAuth
"GOOGLE_CLIENT_ID": "865146315769-vi7vcu91d3i7huv8ikjun52jo9ob7spk.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": os.environ["GOOGLE_CLIENT_SECRET"],
"GOOGLE_REDIRECT_URI": "https://pounce.ch/api/v1/oauth/google/callback",
"GITHUB_CLIENT_ID": "Ov23liBjROk39vYXi3G5",
"GITHUB_CLIENT_SECRET": os.environ["GH_OAUTH_SECRET"],
"GITHUB_REDIRECT_URI": "https://pounce.ch/api/v1/oauth/github/callback",
# CZDS
"CZDS_USERNAME": os.environ["CZDS_USERNAME"],
"CZDS_PASSWORD": os.environ["CZDS_PASSWORD"],
}
lines = []
for k, v in env.items():
if v is None:
continue
lines.append(f"{k}={v}")
path = Path("/data/pounce/env/backend.env")
path.write_text("\n".join(lines) + "\n")
PY
# Build images from synced repo
cd "${{ secrets.DEPLOY_PATH }}"
sudo_cmd docker build -t pounce-backend:latest backend
sudo_cmd docker build \
--build-arg NEXT_PUBLIC_API_URL=https://api.pounce.ch \
--build-arg BACKEND_URL=http://pounce-backend:8000 \
-t pounce-frontend:latest \
frontend
# Deploy backend
sudo_cmd docker stop pounce-backend 2>/dev/null || true
sudo_cmd docker rm pounce-backend 2>/dev/null || true
sudo_cmd docker run -d \
--name pounce-backend \
--network coolify \
--restart unless-stopped \
--shm-size=8g \
--env-file /data/pounce/env/backend.env \
-v /data/pounce/zones:/data \
-l "traefik.enable=true" \
-l "traefik.http.routers.pounce-api.rule=Host(\`api.pounce.ch\`)" \
-l "traefik.http.routers.pounce-api.entryPoints=https" \
-l "traefik.http.routers.pounce-api.tls=true" \
-l "traefik.http.routers.pounce-api.tls.certresolver=letsencrypt" \
-l "traefik.http.services.pounce-api.loadbalancer.server.port=8000" \
pounce-backend:latest
sudo_cmd docker network connect n0488s44osgoow4wgo04ogg0 pounce-backend 2>/dev/null || true
# Deploy frontend
sudo_cmd docker stop pounce-frontend 2>/dev/null || true
sudo_cmd docker rm pounce-frontend 2>/dev/null || true
sudo_cmd docker run -d \
--name pounce-frontend \
--network coolify \
--restart unless-stopped \
-l "traefik.enable=true" \
-l "traefik.http.routers.pounce-web.rule=Host(\`pounce.ch\`) || Host(\`www.pounce.ch\`)" \
-l "traefik.http.routers.pounce-web.entryPoints=https" \
-l "traefik.http.routers.pounce-web.tls=true" \
-l "traefik.http.routers.pounce-web.tls.certresolver=letsencrypt" \
-l "traefik.http.services.pounce-web.loadbalancer.server.port=3000" \
pounce-frontend:latest
sudo_cmd docker network connect n0488s44osgoow4wgo04ogg0 pounce-frontend 2>/dev/null || true
# Health check
sleep 15
curl -sf https://api.pounce.ch/api/v1/health >/dev/null
curl -sf https://pounce.ch >/dev/null
# Cleanup
sudo_cmd docker image prune -f >/dev/null 2>&1 || true
echo "✅ Deploy finished"
DEPLOY_EOF
- name: Summary
run: |
echo "=========================================="
echo "🎉 AUTO DEPLOY COMPLETED"
echo "=========================================="
echo "Commit: ${{ github.sha }}"
echo "Backend: https://api.pounce.ch"
echo "Web: https://pounce.ch"
echo "=========================================="