agentsclimarketplace

Docker vps deploy

Skill itsgitz/agent-skills/docker-vps-deploy

Use when deploying a Dockerized application to a VPS (Linux server) via SSH without a container registry, generating a GitHub Actions pipeline that uses docker save, gzip compression, and rsync to transfer images. Triggers: "deploy to VPS", "rsync docker image", "docker save and load", "VPS CI/CD", "SSH deploy pipeline", "deploy without registry", "transfer docker image via SSH".From its SKILL.md

Install
npx -y skills add itsgitz/agent-skills --skill docker-vps-deploy

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 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 file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

6.8 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it

Docker VPS Deploy

Overview

Build Docker image in CI, compress with gzip, transfer to VPS via rsync over SSH, load and run with Docker Compose. No container registry required — the image travels as a .tar.gz file.

When to Use

  • VPS with SSH access, Docker, and Docker Compose installed
  • No container registry in the workflow (no Docker Hub, ECR, GHCR, etc.)
  • Single-server or small-fleet deployment
  • User asks to generate a GitHub Actions workflow for VPS deployment via rsync/SSH

When NOT to Use

  • Container registry already available → push/pull is simpler and faster
  • Cloud-managed deployments (ECS, Cloud Run, Fly.io, Railway, Render)
  • Multi-node orchestration (Kubernetes, Docker Swarm across nodes)
  • Non-Docker deployments (bare-metal, systemd services)

Prerequisites

On the VPS before first run:

  • Docker and Docker Compose v2 (docker compose, not docker-compose) installed
  • SSH key-based authentication configured for deploy user
  • Deploy directory exists and is writable (e.g., /opt/app)
  • docker-compose.yml present in the repository root

Required Secrets

SecretDescriptionExample
SSH_HOSTVPS IP or hostname203.0.113.10
SSH_USERSSH login userdeploy
SSH_KEYPrivate SSH key (Ed25519 PEM)Contents of ~/.ssh/id_ed25519
SSH_PORTSSH port22

Add in: GitHub repo → Settings → Secrets and variables → Actions.

Core Pipeline Pattern

name: Deploy to VPS

on:
  push:
    branches: [main]
    paths-ignore:
      - "*.md"
      - "docs/**"

env:
  IMAGE_NAME: my-app
  DEPLOY_DIR: /opt/app

jobs:
  deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./Dockerfile
          load: true
          tags: ${{ env.IMAGE_NAME }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Save and compress image
        run: docker save ${{ env.IMAGE_NAME }}:latest | gzip > image.tar.gz

      - name: Setup SSH agent
        uses: webfactory/[email protected]
        with:
          ssh-private-key: ${{ secrets.SSH_KEY }}

      - name: Add VPS to known hosts
        run: ssh-keyscan -p ${{ secrets.SSH_PORT }} -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts

      - name: Transfer files to VPS
        run: |
          rsync -avz \
            -e "ssh -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=yes" \
            image.tar.gz docker-compose.yml \
            ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ env.DEPLOY_DIR }}/

      - name: Deploy on VPS
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          port: ${{ secrets.SSH_PORT }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd ${{ env.DEPLOY_DIR }}
            gunzip -c image.tar.gz | docker load
            docker compose down
            docker compose up -d
            docker image prune -f
            rm -f image.tar.gz

Key Optimizations

  • Layer caching (type=gha, mode=max): GitHub Actions cache backend. Skips rebuild of unchanged layers. mode=max caches all intermediate layers, not just the final stage.
  • Gzip compression: docker save outputs uncompressed tar. Gzip reduces image size 60–70% before transfer. For images >2 GB, consider zstd (docker save ... | zstd) for faster compression.
  • webfactory/ssh-agent: Loads the deploy key into ssh-agent in memory — no key file written to disk. Integrates with the system SSH client, so rsync and other SSH commands work without -i flags.
  • appleboy/ssh-action: Executes remote Docker commands over SSH with a clean YAML interface. Errors and stdout are surfaced natively in the Actions log without manual heredoc handling.
  • rsync -avz: Archive mode + compression during transfer. Subsequent deploys only transfer changed bytes (docker-compose.yml updates are nearly instant).
  • load: true: Required in build-push-action when NOT pushing to a registry. Makes the built image available locally for docker save.

Security Considerations

  • Never use StrictHostKeyChecking=no. Use ssh-keyscan to populate known_hosts before connecting. Disabling host key checking enables MITM attacks.
  • SSH key never written to disk. webfactory/ssh-agent loads the key into ssh-agent in memory. appleboy/ssh-action handles its own key internally — no files, no CLI args.
  • Ed25519 keys preferred over RSA — smaller, faster, same security.
  • Dedicated deploy user on the VPS: non-root, member of docker group, write access to deploy dir only.
  • permissions: contents: read — least-privilege GITHUB_TOKEN scoping.

Common Mistakes

MistakeWhy It FailsFix
Using GHCR/Docker Hub instead of docker saveDoesn't match the no-registry requirement; adds registry credentials complexityUse docker save | gzip > image.tar.gz + rsync
StrictHostKeyChecking=noDisables MITM protectionUse ssh-keyscan + StrictHostKeyChecking=yes
Missing load: true in build stepImage not available locally for docker saveAdd load: true to build-push-action
Using docker-compose (v1 binary)Deprecated; may not exist on VPSUse docker compose (v2 plugin, no hyphen)
No timeout-minutesStuck deploy blocks runner for 6 hoursSet timeout-minutes: 20 on the job
Not cleaning up image.tar.gz on VPSDisk fills up over repeated deploysrm -f image.tar.gz after docker load
Hardcoding SSH port 22Breaks when VPS uses non-standard portParameterize via SSH_PORT secret

Cross-Reference

For GitHub Actions syntax fundamentals — workflow YAML structure, triggers, job orchestration, caching patterns, action SHA pinning, and the 13 common anti-patterns — use the github-actions skill:

npx skills add oakoss/agent-skills/github-actions

This skill focuses exclusively on the Docker + VPS rsync-based deployment pattern and delegates all GitHub Actions syntax questions to that skill.

What ships with it: 1 file

1.4 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.