docker-vps-deploy — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited docker-vps-deploy (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
On the VPS before first run:
docker compose, not docker-compose) installed/opt/app)docker-compose.yml present in the repository root| Secret | Description | Example |
|---|---|---|
SSH_HOST | VPS IP or hostname | 203.0.113.10 |
SSH_USER | SSH login user | deploy |
SSH_KEY | Private SSH key (Ed25519 PEM) | Contents of ~/.ssh/id_ed25519 |
SSH_PORT | SSH port | 22 |
Add in: GitHub repo → Settings → Secrets and variables → Actions.
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.gzmode=max caches all intermediate layers, not just the final stage.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.-i flags.docker-compose.yml updates are nearly instant).build-push-action when NOT pushing to a registry. Makes the built image available locally for docker save.ssh-keyscan to populate known_hosts before connecting. Disabling host key checking enables MITM attacks.webfactory/ssh-agent loads the key into ssh-agent in memory. appleboy/ssh-action handles its own key internally — no files, no CLI args.docker group, write access to deploy dir only.| Mistake | Why It Fails | Fix | |
|---|---|---|---|
Using GHCR/Docker Hub instead of docker save | Doesn't match the no-registry requirement; adds registry credentials complexity | Use `docker save \ | gzip > image.tar.gz` + rsync |
StrictHostKeyChecking=no | Disables MITM protection | Use ssh-keyscan + StrictHostKeyChecking=yes | |
Missing load: true in build step | Image not available locally for docker save | Add load: true to build-push-action | |
Using docker-compose (v1 binary) | Deprecated; may not exist on VPS | Use docker compose (v2 plugin, no hyphen) | |
No timeout-minutes | Stuck deploy blocks runner for 6 hours | Set timeout-minutes: 20 on the job | |
Not cleaning up image.tar.gz on VPS | Disk fills up over repeated deploys | rm -f image.tar.gz after docker load | |
| Hardcoding SSH port 22 | Breaks when VPS uses non-standard port | Parameterize via SSH_PORT secret |
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-actionsThis skill focuses exclusively on the Docker + VPS rsync-based deployment pattern and delegates all GitHub Actions syntax questions to that skill.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.