131 lines
4.7 KiB
YAML
131 lines
4.7 KiB
YAML
# .github/workflows/deploy.yml
|
|
name: Deploy Gateway to VPS
|
|
|
|
on:
|
|
push:
|
|
branches: [ "main" ]
|
|
paths:
|
|
- "docker-compose.yml"
|
|
- "crowdsec/**"
|
|
- "prometheus/**"
|
|
- "grafana/**"
|
|
- ".github/workflows/deploy.yml"
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
REMOTE_DIR: ${{ secrets.REMOTE_DIR }}
|
|
|
|
concurrency:
|
|
group: deploy-prod
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
deploy:
|
|
name: Ship to VPS
|
|
runs-on: ubuntu-latest
|
|
environment: production
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup SSH key
|
|
run: |
|
|
mkdir -p ~/.ssh
|
|
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
|
chmod 600 ~/.ssh/id_rsa
|
|
ssh-keyscan -p "${{ secrets.SSH_PORT }}" "${{ secrets.SSH_HOST }}" >> ~/.ssh/known_hosts
|
|
|
|
- name: Create target dir
|
|
run: |
|
|
ssh -p "${{ secrets.SSH_PORT }}" "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}" "sudo mkdir -p '${REMOTE_DIR}' && sudo chown -R \$USER:\$USER '${REMOTE_DIR}'"
|
|
|
|
- name: Sync repo to VPS (rsync)
|
|
run: |
|
|
rsync -az --delete \
|
|
-e "ssh -p ${{ secrets.SSH_PORT }}" \
|
|
--exclude ".git" \
|
|
--exclude ".github" \
|
|
./ "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${REMOTE_DIR}/"
|
|
|
|
- name: Write .env on VPS (from GitHub Secrets)
|
|
run: |
|
|
ssh -p "${{ secrets.SSH_PORT }}" "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}" \
|
|
"export REMOTE_DIR='${{ secrets.REMOTE_DIR }}'; bash -se" <<'EOF'
|
|
set -euo pipefail
|
|
cd "$REMOTE_DIR"
|
|
|
|
cat > .env <<'ENVVARS'
|
|
# --- Domain / Timezone ---
|
|
DOMAIN=${{ secrets.DOMAIN }}
|
|
TZ=${{ secrets.TZ }}
|
|
|
|
# --- ACME / Let's Encrypt (email only) ---
|
|
ACME_EMAIL=${{ secrets.ACME_EMAIL }}
|
|
|
|
# --- Namecheap DNS API ---
|
|
NAMECHEAP_API_USER=${{ secrets.NAMECHEAP_API_USER }}
|
|
NAMECHEAP_API_KEY=${{ secrets.NAMECHEAP_API_KEY }}
|
|
|
|
# --- CrowdSec ---
|
|
CROWDSEC_BOUNCER_KEY=${{ secrets.CROWDSEC_BOUNCER_KEY }}
|
|
|
|
# --- Umami (PostgreSQL) ---
|
|
UMAMI_DB_USER=${{ secrets.UMAMI_DB_USER }}
|
|
UMAMI_DB_PASS=${{ secrets.UMAMI_DB_PASS }}
|
|
UMAMI_DB_NAME=${{ secrets.UMAMI_DB_NAME }}
|
|
UMAMI_APP_SECRET=${{ secrets.UMAMI_APP_SECRET }}
|
|
|
|
# --- Grafana ---
|
|
GRAFANA_ADMIN_USER=${{ secrets.GRAFANA_ADMIN_USER }}
|
|
GRAFANA_ADMIN_PASS=${{ secrets.GRAFANA_ADMIN_PASS }}
|
|
|
|
# --- Authelia ---
|
|
AUTHELIA_JWT_SECRET=${{ secrets.AUTHELIA_JWT_SECRET }}
|
|
AUTHELIA_SESSION_SECRET=${{ secrets.AUTHELIA_SESSION_SECRET }}
|
|
AUTHELIA_STORAGE_ENCRYPTION_KEY=${{ secrets.AUTHELIA_STORAGE_ENCRYPTION_KEY }}
|
|
# (Optional SMTP if configured)
|
|
AUTHELIA_SMTP_HOST=${{ secrets.AUTHELIA_SMTP_HOST }}
|
|
AUTHELIA_SMTP_PORT=${{ secrets.AUTHELIA_SMTP_PORT }}
|
|
AUTHELIA_SMTP_USER=${{ secrets.AUTHELIA_SMTP_USER }}
|
|
AUTHELIA_SMTP_PASS=${{ secrets.AUTHELIA_SMTP_PASS }}
|
|
AUTHELIA_SMTP_FROM=${{ secrets.AUTHELIA_SMTP_FROM }}
|
|
ENVVARS
|
|
EOF
|
|
|
|
- name: Pre-flight checks (docker + compose)
|
|
run: |
|
|
ssh -p "${{ secrets.SSH_PORT }}" "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}" "
|
|
docker version && docker compose version
|
|
"
|
|
|
|
- name: Deploy (pull, up, prune)
|
|
run: |
|
|
ssh -p "${{ secrets.SSH_PORT }}" "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}" \
|
|
"export REMOTE_DIR='${{ secrets.REMOTE_DIR }}'; bash -se" <<'EOF'
|
|
set -euo pipefail
|
|
cd "$REMOTE_DIR"
|
|
# Warm up networks/volumes and pull images
|
|
docker compose pull
|
|
|
|
# Bring up (idempotent), remove old orphans
|
|
docker compose up -d --remove-orphans
|
|
|
|
# Light cleanup of old images (keeps running ones)
|
|
docker image prune -af || true
|
|
|
|
echo
|
|
echo '--- Running containers ---'
|
|
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
|
|
EOF
|
|
|
|
- name: Post-deploy smoke checks
|
|
run: |
|
|
echo "Deployed to ${{ secrets.SSH_HOST }}:${{ secrets.SSH_PORT }} → ${REMOTE_DIR}"
|
|
echo "Traefik: https://traefik.gate.${{ secrets.DOMAIN }}"
|
|
echo "Portainer: https://portainer.gate.${{ secrets.DOMAIN }}"
|
|
echo "Uptime Kuma: https://uptime.gate.${{ secrets.DOMAIN }}"
|
|
echo "Authelia: https://auth.gate.${{ secrets.DOMAIN }}"
|
|
echo "Grafana: https://grafana.gate.${{ secrets.DOMAIN }}"
|
|
echo "Prometheus: https://prometheus.gate.${{ secrets.DOMAIN }}"
|
|
echo "Umami: https://umami.gate.${{ secrets.DOMAIN }}"
|