Manually uploading files to your VPS via FTP or SCP is error‑prone and time‑consuming. GitHub Actions automates deployment whenever you push code to your repository.
This guide shows you how to set up a GitHub Actions workflow that deploys to a VPS using SSH.
What You'll Need
A GitHub repository with your website code (HTML, PHP, Node.js, etc.), a VPS with SSH access (check our VPS reviews if you need one), and basic knowledge of YAML syntax.
Step 1: Set Up SSH Key Pair
Generate an SSH key pair on your local machine (if you don't have one):
ssh-keygen -t ed25519 -C "github-actions" -f ~/.ssh/github-actions
This creates github-actions (private key) and github-actions.pub (public key).
Add the public key to your VPS:
ssh-copy-id -i ~/.ssh/github-actions.pub user@your_server_ip
Step 2: Add Secrets to GitHub Repository
Go to your GitHub repository → Settings → Secrets and variables → Actions → New repository secret.
Add two secrets:
VPS_HOST– Your server's IP address or domainVPS_USERNAME– Your SSH usernameVPS_SSH_KEY– The content of the private key (~/.ssh/github-actions)
To add the private key, copy the entire file content including -----BEGIN OPENSSH PRIVATE KEY----- and -----END OPENSSH PRIVATE KEY-----.
Step 3: Create GitHub Actions Workflow
In your repository, create a directory .github/workflows/ and add a file named deploy.yml.
name: Deploy to VPS
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup SSH
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts
- name: Deploy via rsync
run: |
rsync -avz --delete ./ user@${{ secrets.VPS_HOST }}:/var/www/html/
This workflow triggers on every push to the main branch. It checks out your code, sets up SSH, then syncs files via rsync.
Step 4: Customize for Your Environment
Adjust the rsync command for your specific setup.
Exclude certain files:
rsync -avz --delete --exclude '.git' --exclude 'node_modules' ./ user@${{ secrets.VPS_HOST }}:/var/www/html/
Run commands after deployment (e.g., restart service):
- name: Restart service
run: |
ssh user@${{ secrets.VPS_HOST }} 'sudo systemctl restart myapp'
Use different branch: Change branches: [ main ] to branches: [ master ] or branches: [ develop ].
Step 5: Test the Workflow
Push a change to your repository's main branch:
git add .
git commit -m "Test deployment"
git push origin main
Go to your repository → Actions tab. You should see the workflow running. After completion, check your VPS to confirm files updated.
Common Issues and Fixes
"Permission denied (publickey)" – Check that the public key is properly added to VPS's ~/.ssh/authorized_keys. Also ensure the private key secret is correct.
"No such file or directory" – The destination directory on VPS may not exist. Create it first via SSH.
"rsync: command not found" – Install rsync on your VPS: sudo apt install rsync -y (Ubuntu) or sudo yum install rsync -y (CentOS).
Next Steps
Once automated deployment works, you can extend the workflow to run tests, build static sites, or notify Slack on success/failure.
Need a VPS to practice on? Check our recommended VPS providers.