deploy

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.

Deploy Skill

Deploy a containerized application to a remote server via Docker and SSH.

Environment Variables

VariableRequiredDescriptionExample
DEPLOY_HOSTYesSSH target (user@host)[email protected]
DEPLOY_IMAGEYesGHCR image pathghcr.io/org/app
DEPLOY_HEALTH_URLNoHealth check endpointhttp://203.0.113.10:3000/health
DEPLOY_CONTAINERNoContainer name (default: image basename)myapp
DEPLOY_DOCKERFILENoDockerfile path (default: ./Dockerfile)./docker/Dockerfile.prod

For first-time server setup, see 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:

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 to build, push, and deploy:

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:

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:

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.