deploy · git:20260222.a812b0b · 2026-02-22 · sha256 b14e4d44bb06c167
deploy git:20260222.a812b0bB
Immutable. This exact content is served forever at /api/v1/blob/b14e4d44bb06c167.
--- name: deploy description: "This skill should be used when deploying containerized applications to remote servers. It builds Docker images, pushes to GHCR, and deploys via SSH with health verification. Triggers on \"deploy\", \"deploy to production\", \"push to server\", \"ship to remote\"." --- # Deploy Skill Deploy a containerized application to a remote server via Docker and SSH. ## Environment Variables | Variable | Required | Description | Example | |----------|----------|-------------|---------| | `DEPLOY_HOST` | Yes | SSH target (user@host) | `root@203.0.113.10` | | `DEPLOY_IMAGE` | Yes | GHCR image path | `ghcr.io/org/app` | | `DEPLOY_HEALTH_URL` | No | Health check endpoint | `http://203.0.113.10:3000/health` | | `DEPLOY_CONTAINER` | No | Container name (default: image basename) | `myapp` | | `DEPLOY_DOCKERFILE` | No | Dockerfile path (default: `./Dockerfile`) | `./docker/Dockerfile.prod` | For first-time server setup, see [hetzner-setup.md](./references/hetzner-setup.md). ## Phase 0: Validate Check prerequisites before starting the build. Run these checks as separate Bash commands: 1. Verify `DEPLOY_HOST` is set: `printenv DEPLOY_HOST` (must produce output) 2. Verify `DEPLOY_IMAGE` is set: `printenv DEPLOY_IMAGE` (must produce output) 3. Verify Docker daemon: `docker info > /dev/null 2>&1` 4. Verify SSH connectivity: `ssh -o ConnectTimeout=5 -o BatchMode=yes <deploy-host> "echo OK"` (replace `<deploy-host>` with the actual DEPLOY_HOST value) 5. Verify Dockerfile exists: `test -f ./Dockerfile` (or the DEPLOY_DOCKERFILE path if set) If any check fails, stop and report the error. Do not proceed to Phase 1. ## Phase 1: Plan Show the deployment summary and ask for confirmation. Use the **AskUserQuestion tool** to present: **Question:** "Deploy this configuration?" **Options:** 1. **Deploy** -- Proceed with build and deployment 2. **Cancel** -- Abort deployment Display before asking: ```text Deployment Plan Image: <DEPLOY_IMAGE>:<git-short-sha> Target: <DEPLOY_HOST> Container: <DEPLOY_CONTAINER or image basename> Dockerfile: <DEPLOY_DOCKERFILE or ./Dockerfile> Health URL: <DEPLOY_HEALTH_URL or none> ``` Resolve `<git-short-sha>` by running `git rev-parse --short HEAD`. If the user selects Cancel, stop execution. ## Phase 2: Execute Run [deploy.sh](./scripts/deploy.sh) to build, push, and deploy: ```bash bash ./plugins/soleur/skills/deploy/scripts/deploy.sh ``` The script handles: 1. Build Docker image tagged with git SHA and `:latest` 2. Push both tags to GHCR 3. SSH to remote host: pull image, stop old container, start new container ## Phase 3: Verify After deployment completes, verify the service is running. **If `DEPLOY_HEALTH_URL` is set:** The deploy script runs a health check (5 attempts, 3s apart). If the health check fails: ```text Health check failed. Debug with: ssh <DEPLOY_HOST> "docker logs <container-name> --tail 50" ``` **If `DEPLOY_HEALTH_URL` is not set:** Report deployment as complete without health verification: ```text Deployed <git-short-sha> to <DEPLOY_HOST> No health URL configured -- skipping verification. ``` ## Important Rules - Never hardcode secrets in the deploy script. Use environment variables. - Never deploy without user confirmation (Phase 1 gate). - The script uses `set -euo pipefail` -- any command failure aborts the deployment. - Container restart uses stop+pull+start, not `docker restart`, to ensure the new image is used.