Files
scopone/.github/skills/deploy-app/SKILL.md
2026-04-10 22:35:01 +02:00

6.5 KiB

name, description
name description
deploy-app Automated deployment of Dockerized applications to remote servers with Gitea registry, Docker Compose orchestration, and Nginx Proxy Manager integration.

Deploy Application

Lean-mode deployment contract for token-efficient execution. Use this file for runtime behavior. For deep examples and full walkthroughs, reference README.md.

Prerequisites

  • DEPLOY_CONFIG_{TARGET} env var exists and is valid JSON
  • SSH host alias works from ~/.ssh/config
  • Dockerfile exists in workspace root
  • Docker available locally and on target server

Deployment Steps

1. Parse target

Extract {TARGET} from user request (for example: deploy productionPRODUCTION).

2. Detect app metadata (minimal set)

Detect and store:

  • {app_name}: from package.json / Cargo.toml / pyproject.toml / go.mod / directory fallback
  • {port}: from EXPOSE, .env PORT, or framework patterns; fallback 3000 (container internal port)
  • {app_type}: webapp, service, or worker
  • {requires_llm}: true if openai|ollama|llama detected
  • {detected_volumes}: bind all host paths under ./data/ (including secrets paths)

If .env* exists (excluding .env.local), process variables into:

  • generated secrets (*SECRET*, *KEY, *TOKEN)
  • inferred service URLs (DATABASE_URL, REDIS_URL, etc.)
  • copied simple values (NODE_ENV, PORT, LOG_LEVEL, ...)
  • user-required values (placeholders/external API keys)

3. Load and validate deploy config

Read DEPLOY_CONFIG_{TARGET} and validate required fields:

  • gitea_registry_url, gitea_username, gitea_token, gitea_namespace
  • ssh_host, stacks_dir

If missing/invalid: STOP with explicit error.

4. Confirm detected configuration

Use ask_questions with detected summary (app, port, type, env, volumes, URL if webapp, deploy mode). If user declines, STOP and request adjustments.

If user-input env values are required, collect them before continuing.

5. Validate and build locally

Verify Dockerfile exists, then run:

  • docker build -t {app_name}:test-build .

If build fails: STOP and report error output.

6. Push image to registry

  1. Login with --password-stdin
  2. Tag as latest and {timestamp} (YYYYMMDD-HHMMSS)
  3. Push both tags

If auth/network/permission fails: STOP with targeted troubleshooting.

7. Detect deploy mode (new vs update)

On remote host and in NPM API (when configured), detect:

  • stack path exists: {stacks_dir}/{app_name}
  • compose file exists: {stacks_dir}/{app_name}/compose.yaml
  • proxy host exists for {app_name}.{domain} (webapp only)

Classification:

  • new: none of the above exist
  • update: stack path or proxy host already exists

If only one side exists (for example proxy exists but stack does not, or inverse), continue in cautious update mode and include this mismatch in confirmation.

8. Prepare remote stack

  1. Verify SSH connectivity
  2. Create {stacks_dir}/{app_name}/data and required subdirectories
  3. Process .env with update-safe merge strategy:
    • if update and remote .env exists, preserve existing keys/values
    • append newly required keys not present remotely
    • never delete existing keys automatically
    • block on unresolved required user-input secrets/placeholders
  4. Apply secure permissions to remote .env (chmod 600)
  5. Handle volume drift safely:
    • create newly required host directories
    • enforce all volume and secrets host paths as children of ./data/
    • keep existing volume paths intact
    • never remove existing volume mounts automatically

9. Generate and upload compose.yaml

Compose requirements:

  • image: {gitea_registry_url}/{gitea_namespace}/{app_name}:latest
  • restart: unless-stopped
  • all volumes and secrets host paths under ./data
  • do NOT publish ports on host (no ports: mapping by default)
  • use external proxy network for webapp
  • add ollama network and OLLAMA_BASE_URL when {requires_llm}=true

Update behavior for compose generation:

  • keep service naming stable for idempotent updates
  • preserve existing mounts/networks unless user explicitly confirms removal
  • if update and env + volume definitions are unchanged, do NOT rewrite compose.yaml
  • if update requires compose rewrite, fetch remote compose.yaml and use it as template baseline before applying required deltas

Upload compose file to {stacks_dir}/{app_name}/compose.yaml.

10. Deploy on server

On remote host:

  1. docker login to registry
  2. docker compose down
  3. docker compose pull
  4. docker compose up -d
  5. Inspect logs (--tail=50) after short wait

If container exits or logs show startup failure: STOP and report logs.

11. Configure reverse proxy (webapp only)

If {app_type}=webapp and NPM config exists:

  1. Authenticate to NPM API
  2. Check if proxy host for {app_name}.{domain} already exists
  3. Set upstream target to Docker service name + internal container port ({app_name}:{port}) on shared proxy network
  4. If existing: update upstream target and SSL settings (idempotent update)
  5. If not existing: create proxy host, request certificate, then enable SSL

If SSL creation fails: WARN and continue HTTP-only.

12. Verify deployment

  • Webapp: curl -I https://{app_name}.{domain} and expect 2xx/3xx
  • Non-webapp: verify running container and health/log readiness

Return structured success summary (image, host, location, URL/container).

Error Recovery

On failure:

  1. Show concrete error
  2. Provide immediate remediation steps
  3. STOP (no implicit continuation)
  4. Offer rollback option using ONLY non-destructive actions:
    • run docker compose down in the app stack directory
    • rollback changes in Nginx Proxy Manager (remove/disable created proxy host entries for this deploy)

Forbidden Operations

Safety policy for this skill is strict:

  • NEVER execute deletion commands on local or remote systems.
  • NEVER run any rm-family or delete operations, including recursive deletes.
  • NEVER use destructive cleanup commands that remove files, directories, volumes, or containers.

Allowed remediation is limited to:

  • docker compose down
  • rollback changes in Nginx Proxy Manager

If a remediation path would require deletion, STOP and report manual follow-up steps without executing destructive commands.

Security

  • Never print secrets in logs
  • Use --password-stdin for all docker logins
  • Quote shell variables
  • Validate all required inputs before executing remote operations

Notes

  • Keep runtime behavior minimal and deterministic.
  • For advanced examples, edge-case recipes, and setup wizard usage, see README.md.