
If you build websites or apps, you know the pain of moving files by hand every time you change something. A GitHub Actions deploy to VPS workflow fixes this. It moves your code to your server the moment you push it. This guide shows you how to set it up step by step. It is written for beginners, so no big words or hard steps. By the end, you will have a working pipeline that saves you hours every week.
What You’ll Build: GitHub Actions Deploy to VPS Overview
Before we start, let’s see what we are building. A GitHub Actions deploy to VPS setup is a set of rules that tells GitHub to send your code to your server. It runs on every push, or on every merge to the main branch. You write the rules once, and they work forever.
Why Automate VPS Deployment with GitHub Actions
Manual deploys are slow and risky. You might forget a file, or break something on the server. A GitHub Actions deploy to VPS flow does three big things for you:
- It saves time. You push code, and the server updates on its own.
- It cuts mistakes. The same steps run every time, with no human error.
- It keeps a log. You can see what was deployed, when, and by whom.
For small teams or solo devs, this is a huge win. You spend less time on ops and more time on building.
Deployment Architecture Overview
The setup has three parts. First, your code lives on GitHub. Second, GitHub Actions runs a workflow file when you push. Third, the workflow uses SSH to copy files to your VPS and restart your app. Think of it like a mail robot that takes your new code from GitHub to your server.
Prerequisites for GitHub Actions Deploy to VPS
Before you start, make sure you have a few things ready. This part is short, but do not skip it. Missing one item will block you later.
Required Tools and Accounts
- A GitHub account (free plan works fine).
- A VPS from any provider (DigitalOcean, Hetzner, Linode, AWS Lightsail, etc.).
- A basic terminal on your computer (Terminal on Mac, PowerShell or CMD on Windows).
- A project with a Git repo already on GitHub.
VPS Server Setup Requirements
Your VPS should run a Linux system like Ubuntu 22.04 or 24.04. It needs SSH access turned on. You should be able to log in as root or a sudo user. Make sure port 22 (or a custom SSH port) is open in your firewall.
GitHub Repository Preparation
Your repo should have a working app. It can be Node.js, PHP, Python, or even plain HTML. The workflow we build will copy files from the repo to a folder on your VPS. That folder is where your app runs from.
Step 1: Generate SSH Keys for GitHub Actions Deploy to VPS
SSH keys are like a special key and lock. The key stays with GitHub, and the lock sits on your VPS. When GitHub wants to send files, it shows the key, and the VPS opens the door.
Create an ED25519 SSH Key Pair
Open your terminal and run this command:
ssh-keygen -t ed25519 -C “github-actions-deploy” -f ~/.ssh/github_actions_deploy
Press Enter when it asks for a passphrase. Leave it empty. This makes a pair of files: a private key (github_actions_deploy) and a public key (github_actions_deploy.pub). The private key is secret. The public key goes on your VPS.
Add the Public Key to Your VPS
Copy the public key to your VPS with this command:
ssh-copy-id -i ~/.ssh/github_actions_deploy.pub your_user@your_vps_ip
Type your VPS password once. After that, you can log in without a password. Test it by running ssh your_user@your_vps_ip. It should log you in right away.
Create a Dedicated Deploy User (Recommended)
For safety, make a new user on the VPS just for deploys. Run these on your VPS:
- sudo adduser deployer
- sudo usermod -aG sudo deployer
- sudo mkdir /home/deployer/.ssh
- sudo cp ~/.ssh/authorized_keys /home/deployer/.ssh/
- sudo chown -R deployer:deployer /home/deployer/.ssh
Now GitHub Actions will log in as deployer, not root. This is much safer.
Step 2: Configure GitHub Secrets for VPS Deployment
Secrets are safe boxes inside your GitHub repo. Only the workflow can open them. You will put your SSH key and server info in these boxes.
Store the SSH Private Key in GitHub Secrets
Open your terminal and print the private key:
cat ~/.ssh/github_actions_deploy
Copy all the output. Then go to your GitHub repo, click Settings, then Secrets and variables, then Actions. Click New repository secret. Name it SSH_PRIVATE_KEY. Paste the key as the value. Click Add secret.
Add Server Host, Port, and Username Variables
Add three more secrets in the same place:
- VPS_HOST: your server IP or domain (e.g., 123.45.67.89)
- VPS_PORT: SSH port, usually 22
- VPS_USER: the deploy user name (e.g., deployer)
Set Up Environment-Specific Secrets (Staging vs Production)
If you have a staging server and a production server, use GitHub Environments. Go to Settings, then Environments. Create two: staging and production. Add secrets to each one. In your workflow, you can pick which environment to use. This keeps your staging and production deploys apart.
Step 3: Write the GitHub Actions Workflow to Deploy to VPS
Now we write the rules file. This file tells GitHub what to do when you push code.
Create the deploy.yml Workflow File
In your repo, make a folder called .github/workflows. Inside it, make a file called deploy.yml. Paste this starter code:
name: Deploy to VPS
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
Configure SSH Connection and File Transfer
Add a step to set up SSH and copy files. Use the popular appleboy/ssh-action or burnett01/rsync-deployments action. Here is a simple version with rsync:
– name: Deploy via rsync
uses: burnett01/rsync-deployments@7.0.0
with:
switches: -avzr –delete
path: ./
remote_path: /var/www/myapp/
remote_host: ${{ secrets.VPS_HOST }}
remote_user: ${{ secrets.VPS_USER }}
remote_port: ${{ secrets.VPS_PORT }}
remote_key: ${{ secrets.SSH_PRIVATE_KEY }}
This step copies all files from your repo to /var/www/myapp/ on the VPS. The –delete flag removes old files that are no longer in the repo.
Add Post-Deployment Commands (Restart Services, Run Migrations)
After files are copied, you may need to restart your app or run database migrations. Add another step that uses appleboy/ssh-action:
– name: Run post-deploy commands
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.VPS_PORT }}
script: |
cd /var/www/myapp
npm install –production
pm2 restart myapp
Complete Workflow Example for Node.js Apps
Here is the full deploy.yml for a Node.js app using a GitHub Actions deploy to VPS flow:
name: Deploy to VPS
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
– name: Deploy via rsync
uses: burnett01/rsync-deployments@7.0.0
with:
switches: -avzr –delete
path: ./
remote_path: /var/www/myapp/
remote_host: ${{ secrets.VPS_HOST }}
remote_user: ${{ secrets.VPS_USER }}
remote_port: ${{ secrets.VPS_PORT }}
remote_key: ${{ secrets.SSH_PRIVATE_KEY }}
– name: Restart app
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.VPS_PORT }}
script: cd /var/www/myapp && npm install –production && pm2 restart myapp
GitHub Actions Deploy to VPS: Stack-Specific Variations
Different apps need slightly different steps. Here are quick tweaks for three common stacks.
Deploy a Docker Application to VPS
For Docker apps, you do not copy files. Instead, you build an image, push it to a registry, then pull it on the VPS. The post-deploy step runs docker compose pull and docker compose up -d. Make sure Docker and Docker Compose are installed on your VPS.
Deploy a Static Site to VPS
Static sites are the easiest. Just use rsync to copy the build folder to your web root, like /var/www/html. No restart is needed. Nginx or Apache will serve the new files right away.
Deploy a Laravel/PHP Application to VPS
For Laravel, copy the files, then run these commands on the VPS:
- composer install –no-dev
- php artisan migrate –force
- php artisan config:cache
- php artisan route:cache
- chmod -R 775 storage bootstrap/cache
Put these in the post-deploy SSH step of your GitHub Actions deploy to VPS workflow.
Secure Your GitHub Actions Deploy to VPS Setup
Security matters. A weak setup can let bad actors into your server. Follow these three rules.
Implement Least-Privilege SSH Access
The deploy user should only be able to do what it needs. Do not give it full root. Lock its SSH key to only run certain commands by editing the authorized_keys file on the VPS. Add a command=”…” prefix to the key line.
Rotate SSH Keys Regularly
Every 90 days, make a new key pair. Add the new public key to the VPS, update the GitHub secret, then delete the old key. This limits the damage if a key is leaked.
Enable GitHub Secret Scanning and Alerts
Go to your repo Settings, then Code security and analysis. Turn on Secret scanning and Push protection. GitHub will block any push that has a secret in it. This stops you from leaking your SSH key by accident.
Troubleshooting GitHub Actions Deploy to VPS Failures
Things will break. That is normal. Here is how to fix the most common issues.
Fix SSH Connection and Permission Denied Errors
If you see “Permission denied (publickey)”, check these:
- The private key in GitHub Secrets has no extra spaces or missing lines.
- The public key is in /home/deployer/.ssh/authorized_keys on the VPS.
- The .ssh folder is mode 700 and authorized_keys is mode 600.
- The deploy user owns the .ssh folder.
Resolve Workflow Timeout and Build Failures
If the workflow times out, your VPS might be slow or the file set is too big. Add a timeout-minutes: 10 line to the job. If npm install fails on the VPS, check that Node.js is installed and in the PATH for the deploy user.
Debug Deployment Script Issues on the VPS
SSH into your VPS by hand and run the same commands the workflow runs. This shows you the real error. Add set -x at the top of your script block to print each command before it runs.
Advanced: Rollback, Monitoring, and Notifications for VPS Deployments
Once your GitHub Actions deploy to VPS flow works, you can add smart features on top.
Set Up Automatic Rollback on Failure
Keep a backup folder on the VPS. Before rsync runs, copy the current app to /var/www/myapp-backup. If the deploy step fails, add a rollback step that copies the backup back. This gets your site up in seconds.
Add Health Checks After Deployment
After the deploy, add a step that curls your site URL. If it does not return 200, fail the job. This catches broken deploys before users see them.
Send Slack or Discord Notifications on Deploy Status
Use the slackapi/slack-github-action or a Discord webhook step. Send a message on success or failure. Your team will know right away when a deploy happens.
FAQ: GitHub Actions Deploy to VPS
How Do I Deploy to Multiple VPS Servers with GitHub Actions?
Use a matrix strategy in your workflow. List each server as a matrix entry. GitHub will run the deploy job for each one in parallel. Give each server its own set of secrets, or use GitHub Environments.
Can I Use GitHub Actions to Deploy to a VPS Without SSH Keys?
Yes, but it is not advised. You can use a username and password with the appleboy/ssh-action. But passwords are weaker than keys. Always use SSH keys for a GitHub Actions deploy to VPS setup.
How Do I Handle Database Migrations When Deploying to VPS?
Put migration commands in the post-deploy SSH step. For Laravel, use php artisan migrate –force. For Node.js with Prisma, use npx prisma migrate deploy. Always back up your database before running migrations in production.
What Is the Best Deployment Strategy for a VPS?
For most small apps, a simple rsync plus service restart is enough. For bigger apps, use a blue-green setup with two folders and a symlink. Point the symlink to the new folder after the deploy. This gives you zero-downtime deploys.
Conclusion: Start Automating Your VPS Deployments with GitHub Actions Today
You now have everything you need to build a GitHub Actions deploy to VPS workflow. You learned how to make SSH keys, set up GitHub secrets, write the deploy.yml file, and handle different app stacks. You also know how to keep the setup safe and fix common errors.
Start small. Deploy a test project first. Once it works, move your real apps over. You will save time, cut mistakes, and sleep better at night. The next step is to add rollback, health checks, and notifications. Happy deploying!
