This guide walks you through:
- Provisioning a fresh Hetzner (Ubuntu) VPS
- Generating an SSH key for GitHub Actions → VPS
- Installing Docker & Docker Compose
- Creating your app directory
- Wiring up GitHub Actions to deploy via SSH and Docker Compose
On your VPS as root:
# Upload the script (either via scp or direct paste):
cat > /root/setup_vps.sh <<'EOF'
$(sed 's/^/ /' <<EOF
$script_content
EOF
)
EOF
chmod +x /root/setup_vps.sh
/root/setup_vps.sh- At the end it will print a new private key.
- Copy everything between the
COPY THIS PRIVATE KEYmarkers.
Go to YourRepo → Settings → Secrets and Variables → Actions and add:
VPS_HOST= your VPS IP or hostnameVPS_USER= the deploy user (default:deployer)VPS_SSH_KEY= paste the private key from step 1VPS_SSH_PASSPHRASE= leave blank (we generated with no passphrase)REMOTE_APP_PATH=/home/deployer/{APP-DIR}
From your local machine:
ssh -i actions-to-vps deployer@your.vps.ip docker compose versionYou should see Docker Compose’s version output without a password prompt.
Your GitHub Actions will SSH into $REMOTE_APP_PATH and deploy files.
You don’t need to git clone on the VPS.
Ensure that your workflow copies:
docker-compose.local.ymldocker-compose.prod.ymlDockerfileapp/(your code)CaddyfileandCaddyfile.localconfig/.env.prodor.env.local
into $REMOTE_APP_PATH.
Key job in your .github/workflows/main.yml:
vps-deploy:
if: github.ref == 'refs/heads/vps-test'
name: 🚀 Deploy to VPS Test Environment
runs-on: ubuntu-latest
steps:
- name: 🚚 Checkout code
uses: actions/checkout@v3
- name: 📁 Copy entire repo to VPS via SFTP
uses: appleboy/scp-action@v0.1.0
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
passphrase: ${{ secrets.VPS_SSH_PASSPHRASE }}
port: 22
source: "." # <-- copy everything
target: ${{ secrets.REMOTE_APP_PATH }}
recursive: true
- name: 🔑 SSH & rebuild on VPS
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
passphrase: ${{ secrets.VPS_SSH_PASSPHRASE }}
port: 22
script: |
set -e
cd ${{ secrets.REMOTE_APP_PATH }}
echo "⏳ Pulling latest images & rebuilding with prod compose…"
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --build-
Push to your
vps-testbranch → watch the CI deploy automatically. -
Merge to
main(orstaging) to trigger other environments. -
Enjoy zero-downtime, GitHub-driven deployments!
Note : SSH into the vps using
ssh root@<VPS-IP>and use the password set for the vps