Files
launchpad-gateway/.github/workflows/deploy.yml

119 lines
4.0 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 }}
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 "Status (Kuma): https://status.gate.${{ secrets.DOMAIN }}"
echo "Grafana: https://grafana.gate.${{ secrets.DOMAIN }}"
echo "Prometheus: https://prometheus.gate.${{ secrets.DOMAIN }}"
echo "Umami: https://umami.gate.${{ secrets.DOMAIN }}"