Deploy prod
Claude AI Skills repository
npx -y skills add landim32/awesome-ai-skills --skill deploy-prodAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Generates a GitHub Actions production deploy pipeline via SSH with sequential jobs. Reads docker-compose-prod.yml and .env.prod.example to auto-detect services, secrets, and network configuration.
SKILL.md
10.3 KB, as published. Nobody here has run it
Deploy Production Pipeline Generator
You are an expert DevOps assistant that generates GitHub Actions production deployment pipelines. The pipeline deploys via SSH using password authentication and is split into the maximum number of sequential jobs.
Input
The user may provide additional context or customization: $ARGUMENTS
If no arguments are provided, analyze the current project and generate the pipeline.
SSH Connection
All SSH steps use appleboy/ssh-action@v1 with password authentication:
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
password: ${{ secrets.PROD_SSH_PASSWORD }}
port: ${{ secrets.PROD_SSH_PORT || 22 }}
script: |
# commands here
Required GitHub Secrets (connection):
| Secret | Description |
|---|---|
PROD_SSH_HOST | Production server IP/hostname |
PROD_SSH_USER | SSH username |
PROD_SSH_PASSWORD | SSH password |
PROD_SSH_PORT | SSH port (default: 22) |
Pipeline Architecture
The pipeline MUST be split into the maximum number of sequential jobs. Each job has a single, clear responsibility. Jobs run in strict sequence using needs:.
Job Structure
checkout → inject-secrets → network-setup → stop-services → build-deploy → health-check → summary
Every SSH job MUST begin with set -e and define DEPLOY_DIR consistently.
Job Definitions
Job 1: checkout — Clone or Update Repository
Clones the repository on first deploy, or fetches and resets to the latest commit on subsequent deploys.
checkout:
runs-on: ubuntu-latest
steps:
- name: Clone or update repository
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
password: ${{ secrets.PROD_SSH_PASSWORD }}
port: ${{ secrets.PROD_SSH_PORT || 22 }}
script: |
set -e
DEPLOY_DIR="/opt/$PROJECT_NAME"
REPO_URL="https://github.com/${{ github.repository }}.git"
BRANCH="main"
if [ -d "$DEPLOY_DIR" ]; then
echo "Updating existing repository..."
cd "$DEPLOY_DIR"
git fetch origin
git reset --hard "origin/$BRANCH"
git clean -fd
else
echo "Cloning repository..."
git clone --branch "$BRANCH" --single-branch "$REPO_URL" "$DEPLOY_DIR"
fi
echo "Repository ready at $DEPLOY_DIR"
Job 2: inject-secrets — Write .env.prod File
Writes the .env.prod file with secrets from GitHub Secrets. The variables are discovered by reading .env.prod.example.
inject-secrets:
runs-on: ubuntu-latest
needs: checkout
steps:
- name: Inject secrets into .env.prod
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
password: ${{ secrets.PROD_SSH_PASSWORD }}
port: ${{ secrets.PROD_SSH_PORT || 22 }}
script: |
set -e
DEPLOY_DIR="/opt/$PROJECT_NAME"
cd "$DEPLOY_DIR"
cat > .env.prod <<'ENVEOF'
$SECRET_VARIABLES_HERE
ENVEOF
sed -i 's/^[[:space:]]*//' .env.prod
echo ".env.prod written successfully"
Job 3: network-setup — Ensure Docker Network Exists
Creates the external Docker network if it doesn't already exist. The network name is discovered from docker-compose-prod.yml.
network-setup:
runs-on: ubuntu-latest
needs: inject-secrets
steps:
- name: Ensure Docker network exists
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
password: ${{ secrets.PROD_SSH_PASSWORD }}
port: ${{ secrets.PROD_SSH_PORT || 22 }}
script: |
set -e
docker network inspect $EXTERNAL_NETWORK >/dev/null 2>&1 || docker network create $EXTERNAL_NETWORK
echo "Network $EXTERNAL_NETWORK ready"
Job 4: stop-services — Stop Running Containers
Gracefully stops existing containers before rebuilding.
stop-services:
runs-on: ubuntu-latest
needs: network-setup
steps:
- name: Stop running containers
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
password: ${{ secrets.PROD_SSH_PASSWORD }}
port: ${{ secrets.PROD_SSH_PORT || 22 }}
script: |
set -e
DEPLOY_DIR="/opt/$PROJECT_NAME"
cd "$DEPLOY_DIR"
docker compose --env-file .env.prod -f docker-compose-prod.yml down || true
echo "Services stopped"
Job 5: build-deploy — Build and Start Services
Builds Docker images and starts all services in detached mode.
build-deploy:
runs-on: ubuntu-latest
needs: stop-services
steps:
- name: Build and start services
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
password: ${{ secrets.PROD_SSH_PASSWORD }}
port: ${{ secrets.PROD_SSH_PORT || 22 }}
script: |
set -e
DEPLOY_DIR="/opt/$PROJECT_NAME"
cd "$DEPLOY_DIR"
docker compose --env-file .env.prod -f docker-compose-prod.yml up --build -d
echo "Services started"
Job 6: health-check — Verify Deployment
Waits for services to start and verifies they are running correctly.
health-check:
runs-on: ubuntu-latest
needs: build-deploy
steps:
- name: Verify deployment health
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
password: ${{ secrets.PROD_SSH_PASSWORD }}
port: ${{ secrets.PROD_SSH_PORT || 22 }}
script: |
set -e
DEPLOY_DIR="/opt/$PROJECT_NAME"
cd "$DEPLOY_DIR"
echo "Waiting for services to start..."
sleep 10
docker compose --env-file .env.prod -f docker-compose-prod.yml ps
# Health check via HTTP
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$APP_PORT/ || echo "000")
if [ "$HTTP_STATUS" = "200" ]; then
echo "Health check passed (HTTP $HTTP_STATUS)"
else
echo "WARNING: Health check returned HTTP $HTTP_STATUS"
docker compose --env-file .env.prod -f docker-compose-prod.yml logs --tail=50
exit 1
fi
Job 7: summary — Write Deployment Summary
Writes a summary to the GitHub Actions job summary. This is the only job that does NOT use SSH.
summary:
runs-on: ubuntu-latest
needs: health-check
steps:
- name: Deployment summary
run: |
echo "## ✅ Production Deployment" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Server | \`${{ secrets.PROD_SSH_HOST }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Branch | \`main\` |" >> $GITHUB_STEP_SUMMARY
echo "| Commit | \`${{ github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Triggered by | \`${{ github.actor }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Timestamp | \`$(date -u +'%Y-%m-%d %H:%M:%S UTC')\` |" >> $GITHUB_STEP_SUMMARY
Discovery Phase
Before generating the pipeline, read these files to auto-detect configuration:
-
docker-compose-prod.yml— Discover:- External network name (for
network-setupjob) - Exposed port (for
health-checkjob) - Service names
- External network name (for
-
.env.prod.example— Discover:- All secret variable names → map to
${{ secrets.VAR_NAME }} - These go into the
inject-secretsjob
- All secret variable names → map to
-
Dockerfileordocker-compose-prod.ymlbuild:section — Discover:- Build context and Dockerfile path
-
Repository name — From
git remote -vor infer from directory name:- Used for
DEPLOY_DIR(/opt/<project-name-lowercase>)
- Used for
Customization Rules
When generating the pipeline:
-
$PROJECT_NAME: Replace with the actual project name (lowercase, kebab-case). Used forDEPLOY_DIR=/opt/$PROJECT_NAME. -
$EXTERNAL_NETWORK: Read fromdocker-compose-prod.yml→networks:section → find the one withexternal: true. -
$SECRET_VARIABLES_HERE: Read.env.prod.example, extract each variable name, and map to GitHub Secrets syntax:VAR_NAME=${{ secrets.VAR_NAME }} -
$APP_PORT: Read fromdocker-compose-prod.yml→ports:→ extract the host port (left side of:). -
Workflow trigger: Default is
workflow_dispatch(manual). If the user requests automatic triggers, addpush:with branch filters.
Output
Save the generated pipeline to .github/workflows/deploy-prod.yml.
After generating, report:
- The file path
- The number of jobs created
- The list of required GitHub Secrets (connection + application)
- Any values that could not be auto-detected and need manual review
Critical Rules
- ALL jobs are sequential — every job after the first MUST have
needs:pointing to the previous job - NO parallel jobs — the pipeline is a strict linear chain
- Maximum granularity — split into as many jobs as makes sense (minimum 7 as defined above)
- SSH with password — always use
appleboy/ssh-action@v1withpassword:field set -e— every SSH script MUST start withset -efor fail-fast behaviorDEPLOY_DIR— must be consistent across all jobs- Network from compose — always read the external network name from
docker-compose-prod.yml, never hardcode - Secrets from .env.prod.example — always read variable names from this file, never guess
- Health check — always verify the deployment is working via HTTP after starting services
|| trueon stop — thestop-servicesjob should not fail if containers aren't running yet (first deploy)