GitHub Actions to VPS: Automated Deployment via SSH
Every time you push code to GitHub, you want it deployed automatically to your VPS. GitHub Actions lets you automate workflows—including continuous deployment directly to your server via SSH—so you can test, build, and deploy without manual SSH sessions.
Every time you push code to GitHub, you want it deployed automatically to your VPS. No manual SSH sessions. No copy-pasting files. No nervous fingers typing commands that might crash your production server.
GitHub Actions makes this possible. It’s GitHub’s built-in CI/CD platform that lets you automate workflows—including continuous deployment directly to your server via SSH. With just a few lines of configuration, you can set up a deployment pipeline that tests your code, builds it, and deploys it to your VPS automatically.
For Indian startups and SMBs managing web applications on cloud servers, this is a game-changer. It eliminates manual deployment errors, speeds up release cycles, and lets your team focus on coding instead of DevOps firefighting.
In this guide, we’ll walk through setting up automated VPS deployment using GitHub Actions, configuring SSH access for CI/CD, and deploying your application automatically on every push.
Why Automate Your Deployment Process?
Before diving into the technical setup, let’s understand why automated deployment workflows matter.
Manual deployment is risky:
- Developers SSH into production and run commands manually (prone to typos and mistakes)
- No audit trail of who deployed what and when
- Deployments happen at different times, making debugging inconsistent
- A single misconfiguration can crash your production environment
- Scaling to multiple servers becomes exponentially harder
Automated deployment is reliable:
- Every deployment follows the exact same steps (consistency)
- Code is tested before deployment (catching bugs early)
- Rollback is simple if something breaks
- Your team can deploy without SSH access to production (security)
- Continuous deployment means features reach users faster
- Audit logs track every deployment automatically
GitHub Actions makes automation affordable:
- Free for public repositories
- Included with GitHub (no extra tools or subscriptions)
- Works seamlessly with your existing GitHub workflow
- Supports deploying to any VPS or cloud server via SSH
Understanding GitHub Actions and SSH Deployment
GitHub Actions is GitHub’s workflow automation platform. It runs jobs on GitHub-hosted runners (virtual machines) whenever events occur—like pushing code to a repository.
A typical GitHub Actions deployment workflow looks like:
- Developer pushes code to
mainbranch - GitHub Actions automatically triggers
- Tests run on the code
- If tests pass, the runner connects to your VPS via SSH
- The runner pulls the latest code and restarts your application
- Users see the new version instantly
This entire process happens in minutes, without human intervention.
Step 1: Generate SSH Keys for GitHub Actions
First, you need to generate a special SSH key pair for GitHub Actions to use when connecting to your VPS.
On your local machine (not the VPS yet):
ssh-keygen -t ed25519 -f gh-actions-deploy -C "github-actions-deploy"
This creates two files:
gh-actions-deploy— Private key (GitHub will use this)gh-actions-deploy.pub— Public key (goes on your VPS)
Do not use your personal SSH key. Using a separate key for CI/CD follows security best practices and lets you revoke GitHub Actions access without affecting personal access.
Step 2: Add the Public Key to Your VPS
SSH into your VPS and add GitHub Actions’ public key to your authorized keys:
ssh root@your-vps-ip-address
Create a dedicated deploy user (best practice for security):
sudo useradd -m -s /bin/bash deploy
sudo mkdir -p /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
Add GitHub Actions’ public key to the deploy user:
echo "your-public-key-content-here" | sudo tee /home/deploy/.ssh/authorized_keys
sudo chmod 600 /home/deploy/.ssh/authorized_keys
sudo chown deploy:deploy /home/deploy/.ssh/authorized_keys
Replace your-public-key-content-here with the contents of gh-actions-deploy.pub from your local machine.
Configure sudo access (so the deploy user can restart services without a password):
sudo visudo
Add this line at the end:
deploy ALL=(ALL) NOPASSWD: /bin/systemctl
This allows the deploy user to run systemctl commands (for restarting your app) without a password prompt.
Step 3: Add the Private Key to GitHub Secrets
Now tell GitHub about the private key so GitHub Actions can use it.
In your GitHub repository:
- Go to Settings → Secrets and variables → Actions
- Click New repository secret
- Name it
DEPLOY_KEY - Paste the entire contents of
gh-actions-deploy(the private key file) - Click Add secret
Also add these secrets:
DEPLOY_HOST— Your VPS IP address (e.g.,203.0.113.45)DEPLOY_USER— The deploy user (e.g.,deploy)APP_DIRECTORY— Where your app lives on the VPS (e.g.,/home/deploy/myapp)
Step 4: Create a GitHub Actions Workflow
In your repository root, create .github/workflows/deploy.yml:
name: Deploy to VPS
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to VPS via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
script: |
cd ${{ secrets.APP_DIRECTORY }}
git pull origin main
npm install
npm run build
sudo systemctl restart myapp
What this workflow does:
- Triggers whenever code is pushed to the
mainbranch - Checks out your latest code
- Connects to your VPS via SSH using the deploy key
- Pulls the latest code from GitHub
- Installs dependencies and builds your app
- Restarts your application service
Customize the script section for your app:
- If you use Python/Django: replace npm commands with
pip installandpython manage.py migrate - If you use Node.js: use
npm install && npm run build - If you use Go: replace with
go build -o myapp
Step 5: Test Your Deployment Workflow
Push a small change to your main branch:
git add .
git commit -m "Test deployment"
git push origin main
Watch the deployment in real-time:
- Go to your GitHub repository
- Click the Actions tab
- You’ll see your workflow running
- Click the workflow name to see step-by-step logs
If all steps pass (green checkmarks), your deployment succeeded. SSH into your VPS and verify the latest code is live:
ssh deploy@your-vps-ip-address
cd /home/deploy/myapp
git log --oneline -n 1
You should see your commit message, confirming the code was deployed.
Step 6: Advanced Configuration (Optional)
Only deploy on successful tests
Add a test step before deployment:
- name: Run Tests
run: npm test
- name: Deploy to VPS
if: success()
uses: appleboy/ssh-action@master
Deploy to multiple VPS instances
- name: Deploy to Production
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
script: |
cd ${{ secrets.APP_DIRECTORY }}
git pull origin main
npm install && npm run build
sudo systemctl restart myapp
- name: Deploy to Staging
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.STAGING_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
script: |
cd ${{ secrets.APP_DIRECTORY }}
git pull origin main
npm install && npm run build
sudo systemctl restart myapp
Add deployment notifications
Notify Slack when deployment succeeds or fails:
- name: Notify Slack on Success
if: success()
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-H 'Content-Type: application/json' \
-d '{"text":"Deployment to VPS succeeded! 🚀"}'
Hostzop Cloud: Simplify Deployment Workflows for Your VPS
Managing continuous deployment and CI/CD pipelines across multiple production servers adds complexity that most Indian startups don’t have time for. Hostzop Cloud empowers teams to Automate VPS Deployments with seamless GitHub Actions integration, flexible server configurations, and expert guidance on deployment best practices. Whether you’re setting up your first automated deployment workflow or scaling across multiple instances, Hostzop Cloud’s VPS platform provides the infrastructure stability, SSH security, and responsive support needed for reliable continuous delivery. With transparent pricing starting from affordable INR rates and no hidden deployment costs, Hostzop Cloud is the trusted choice for Indian businesses looking to automate application deployment without overcomplicating their DevOps setup.
Troubleshooting Common Issues
“Permission denied” errors:
- Verify the public key is correctly added to
authorized_keys - Ensure the
.sshdirectory permissions are700andauthorized_keysis600 - Confirm the deploy user exists on your VPS
“Git pull fails” during deployment:
- Ensure your VPS has git installed:
sudo apt install git - Verify the repository is cloned at
$APP_DIRECTORY - Check that the deploy user has read/write permissions to the directory
“Deployment succeeds but app doesn’t restart”:
- Verify the systemctl service name is correct
- Check that the deploy user has sudo access to systemctl:
sudo visudo - Check service logs:
sudo journalctl -u myapp -n 20
Frequently Asked Questions
Is it safe to give GitHub Actions SSH access to my production VPS?
Yes, if you follow best practices: use a dedicated deploy key (not your personal SSH key), create a dedicated deploy user with limited permissions, restrict the deploy user’s ability to run only necessary commands (via sudo rules), and rotate the deploy key periodically. This is far safer than storing production passwords or giving developers SSH access.
Can I deploy different branches to different environments?
Yes. Create multiple workflows or use conditional logic:
on:
push:
branches:
- main
- staging
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Production
if: github.ref == 'refs/heads/main'
What if a deployment fails? How do I rollback?
SSH into your VPS and revert the last commit:
cd /home/deploy/myapp
git revert HEAD
git pull origin main
sudo systemctl restart myapp
Or create a GitHub Actions workflow to automate rollbacks.
How do I prevent deployments during business hours to avoid downtime?
Add a schedule condition:
on:
push:
branches: [main]
schedule:
- cron: '0 2 * * 1-5' # 2 AM Monday-Friday only
Can GitHub Actions deploy to multiple VPS at once?
Yes. Add multiple deploy steps in the same job, each connecting to a different VPS using different secrets (PROD_HOST_1, PROD_HOST_2, etc.). They run sequentially, so all servers deploy consistently.
How do I know if a deployment succeeded?
Check the GitHub Actions logs (in the Actions tab), or add Slack/email notifications. You can also SSH into your VPS and verify the code is live by checking the git log or app version.
What happens if I push to main before the previous deployment finishes?
GitHub Actions queues workflows sequentially by default, so the second push waits for the first deployment to complete. This prevents race conditions.