Back to all guides
12 Jun 2026 3 min read 597 words

How to Build a Complete CI/CD Pipeline for VPS Hosting Using GitHub Actions

Manual deployment—SSHing into a server, pulling code, and restarting services—is a ritual that invites human error. As your project grows, this process becomes a bottleneck. Building a Continuous Integration (CI) and Continuous Deployment (CD) pipeline using GitHub Actions.

How to Build a Complete CI/CD Pipeline for VPS Hosting Using GitHub Actions hero image

Manual deployment—SSHing into a server, pulling code, and restarting services—is a ritual that invites human error. As your project grows, this process becomes a bottleneck. Building a Continuous Integration (CI) and Continuous Deployment (CD) pipeline using GitHub Actions automates this entire flow, ensuring that every push to your repository results in a tested, deployed, and live application.

In this guide, we will walk through creating a robust pipeline designed specifically for Virtual Private Server (VPS) environments.

Understanding the Architecture

A modern CI/CD pipeline acts as a bridge between your local development environment and your production server. The flow typically follows these stages:

  1. Trigger: You push code changes to a specific branch (e.g., main).
  2. Continuous Integration (CI): GitHub Actions starts an ephemeral runner, installs dependencies, runs linters, and executes test suites.
  3. Continuous Deployment (CD): Only if the tests pass, the runner connects securely to your VPS via SSH to update the application code and restart the necessary processes.

Building Your GitHub Actions Pipeline

1. Prerequisites

Before configuring the pipeline, ensure you have the following:

  • A GitHub Repository: Containing your application source code.
  • A Linux VPS: With SSH access configured.
  • SSH Key Authentication: Never use password authentication for automated deployments.

Preparing SSH Access

Generate a dedicated SSH key pair for your CI/CD service:

# Run this on your local machine
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_actions_deploy

Copy the public key (.pub) to your VPS inside /home/deploy/.ssh/authorized_keys. The private key will be added to GitHub.

2. Configuring GitHub Secrets

You must never hardcode server IP addresses or private keys in your workflow files. Use GitHub Secrets to keep these credentials secure.

  1. Navigate to your repository on GitHub.
  2. Go to Settings → Secrets and variables → Actions.
  3. Add the following repository secrets:
    • SSH_PRIVATE_KEY: Paste the contents of your GitHub Actions deploy private key.
    • VPS_HOST: The IP address of your VPS.
    • VPS_USER: The username created on your VPS (e.g., deploy).

3. Defining the Workflow

Create a file at .github/workflows/deploy.yml in your repository. This YAML file tells GitHub how to handle your code.

name: Deploy to VPS

on:
  push:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with: { node-version: '22' }
      - run: npm install
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to VPS
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/myapp
            git pull origin main
            npm install --production
            pm2 restart myapp || pm2 start npm --name "myapp" -- start

4. Security and Maintenance Best Practices

  • Dedicated Deploy User: Do not use root for automated deployments. Create a dedicated user with minimal permissions required to restart your specific application services.
  • Use GitHub Environments: Define an environment (e.g., “Production”) within your repository settings to gate your deployments. This configuration allows you to require manual approval from a team member before the deployment proceeds, ensuring you maintain total control over your production releases.
  • Caching Dependencies: To speed up your CI phase, use the actions/cache step to persist node_modules or pip packages across runs.
  • Ephemeral Runners vs. Self-Hosted: GitHub-hosted runners are perfect for most projects. However, if your build requires high-performance hardware, local network access, or specialized software, consider using a self-hosted runner directly on your infrastructure.

Conclusion

By moving from manual terminal commands to an automated pipeline, you gain consistency, faster deployment cycles, and, most importantly, the ability to test your code before it ever touches your server. With GitHub Actions, you have a free, integrated, and highly extensible tool to manage your deployments professionally.