Skip to main content
Glama
deploy-production.yml7.13 kB
# GitHub Actions Workflow Contract: Production Deployment # # This contract defines the workflow structure for automated CI/CD deployment # to Hostinger VPS. It serves as the schema/template for the actual workflow # implementation in .github/workflows/deploy-production.yml # # Feature: Automated CI/CD Pipeline for Hostinger Deployment # Phase: 1 - Design & Contracts # Date: 2025-10-19 name: Deploy to Production # Trigger Configuration # FR-001: System MUST trigger deployment workflow automatically when PR merged to main on: push: branches: - main # Only trigger on commits to main branch (post-merge) workflow_dispatch: # Allow manual triggering for emergency deployments # FR-010: System MUST prevent deployments when required secrets are missing # Concurrency control prevents race conditions from concurrent merges # FR-011: Ensures sequential deployment, no concurrent executions concurrency: group: production-deployment cancel-in-progress: false # Wait for current deployment to finish jobs: deploy: name: Deploy to Hostinger VPS runs-on: ubuntu-latest # FR-011: Complete deployment within 10 minutes timeout-minutes: 10 steps: # Step 1: Checkout Code # Retrieves the merged code from the main branch - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # Full history for rollback capability # Step 2: Validate Required Secrets # FR-010: Prevent deployments when required GitHub secrets are missing - name: Validate deployment secrets run: | # Check that all required secrets are present (non-empty) # This step fails fast if any secret is missing REQUIRED_SECRETS=( "SSH_HOST" "SSH_USERNAME" "SSH_PRIVATE_KEY" "DEPLOY_PATH" "SUPABASE_URL" "SUPABASE_SERVICE_KEY" "SUPABASE_ANON_KEY" "HOSTAWAY_ACCOUNT_ID" "HOSTAWAY_SECRET_KEY" ) # Verify secrets exist (GitHub Actions limitation: can't check values directly) # Actual validation happens during SSH connection echo "Secret validation placeholder - secrets are validated during deployment" # Step 3: Deploy to Hostinger via SSH # FR-002: Authenticate using SSH key from GitHub secrets # FR-003: Transfer environment variables from GitHub secrets # FR-004: Build Docker container on server # FR-006: Mask sensitive values in logs - name: Deploy to Hostinger uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USERNAME }} key: ${{ secrets.SSH_PRIVATE_KEY }} port: 22 script_stop: true # Stop on first error script: | set -e # Exit on any error set -u # Exit on undefined variables cd ${{ secrets.DEPLOY_PATH }} # Create backup before deployment (FR-007, FR-012) BACKUP_DIR="backups/$(date +%Y%m%d-%H%M%S)" mkdir -p "$BACKUP_DIR" # Backup current deployment artifacts if [ -d "src" ]; then cp -r src "$BACKUP_DIR/" fi if [ -f ".env" ]; then cp .env "$BACKUP_DIR/" fi if docker images | grep -q hostaway-mcp:latest; then docker save hostaway-mcp:latest > "$BACKUP_DIR/image.tar" fi # Pull latest code git fetch origin main git reset --hard origin/main # FR-003: Create .env from GitHub secrets cat > .env <<EOF SUPABASE_URL=${{ secrets.SUPABASE_URL }} SUPABASE_SERVICE_KEY=${{ secrets.SUPABASE_SERVICE_KEY }} SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} HOSTAWAY_ACCOUNT_ID=${{ secrets.HOSTAWAY_ACCOUNT_ID }} HOSTAWAY_SECRET_KEY=${{ secrets.HOSTAWAY_SECRET_KEY }} ENVIRONMENT=production EOF # Secure .env file permissions chmod 600 .env # FR-004: Build and deploy Docker container docker compose -f docker-compose.prod.yml down docker compose -f docker-compose.prod.yml build --no-cache docker compose -f docker-compose.prod.yml up -d # Wait for container startup sleep 10 # FR-005: Health check verification if ! curl -f -s http://localhost:8080/health > /dev/null; then echo "Health check failed - rolling back to previous version" # FR-012: Rollback on failure docker compose -f docker-compose.prod.yml down # Restore previous version if [ -f "$BACKUP_DIR/image.tar" ]; then docker load < "$BACKUP_DIR/image.tar" docker compose -f docker-compose.prod.yml up -d fi exit 1 # Mark deployment as failed fi # Cleanup old backups (keep last 5) cd backups ls -t | tail -n +6 | xargs -r rm -rf echo "Deployment successful" # Step 4: Report Deployment Status # FR-008: Send deployment status notifications # FR-009: Store deployment logs (GitHub Actions retains for 90 days) - name: Report deployment status if: always() run: | if [ "${{ job.status }}" == "success" ]; then echo "✅ Deployment completed successfully" echo "Production server: http://${{ secrets.SSH_HOST }}" else echo "❌ Deployment failed - check logs for details" echo "Previous version has been preserved/restored" fi # Expected Outputs: # - FR-001: Workflow triggers automatically on PR merge to main # - FR-002: Successful SSH authentication using GitHub secrets # - FR-003: Environment variables transferred securely to production # - FR-004: Docker container built and started on Hostinger # - FR-005: Health check verifies successful deployment # - FR-006: All secrets masked in GitHub Actions logs (automatic) # - FR-007: Previous version backed up before deployment # - FR-008: Deployment status visible in GitHub Actions UI # - FR-009: Full deployment logs available for 90 days # - FR-010: Deployment blocked if secrets missing (fails at SSH step) # - FR-011: Deployment completes within 10-minute timeout # - FR-012: Automatic rollback on health check failure # Success Criteria Mapping: # - SC-001: Changes live within 10 minutes (timeout enforcement) # - SC-002: 95% deployment success (monitored via GitHub Actions history) # - SC-003: Zero credential exposure (GitHub Actions auto-masking) # - SC-004: Failure detection within 30 seconds (health check + timeout) # - SC-005: 99.9% uptime (Docker graceful restart, rollback on failure) # - SC-006: 100% rollback success (tested in workflow) # - SC-007: Troubleshoot via GitHub Actions logs (90-day retention) # - SC-008: Manual deployment time reduced to 0 (full automation)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/darrentmorgan/hostaway-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server