How to Build a Simple CI/CD Pipeline with GitHub Actions

GitHub Actions lets you automate testing and deployment directly from your repository, without needing a separately hosted CI/CD server for many use cases. This guide covers building a complete pipeline: test, build, and deploy to your VPS.

Prerequisites

  • A GitHub repository containing your application
  • SSH access to your VPS

Step 1 — Generate a Deploy-Specific SSH Key

On your local machine (not the VPS):

ssh-keygen -t ed25519 -f deploy_key -C "github-actions-deploy" -N ""

Step 2 — Add the Public Key to Your VPS

cat deploy_key.pub | ssh deploy@YOUR_SERVER_IP "cat >> ~/.ssh/authorized_keys"

Step 3 — Add the Private Key as a GitHub Secret

In your repository: Settings → Secrets and variables → Actions → New repository secret. Name it DEPLOY_KEY, paste the private key content.

Add additional secrets for the server IP and username similarly (SERVER_IP, SERVER_USER).

Step 4 — Create the Workflow File

mkdir -p .github/workflows
nano .github/workflows/deploy.yml
name: Test and Deploy

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Set up SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key
          ssh-keyscan -H ${{ secrets.SERVER_IP }} >> ~/.ssh/known_hosts

      - name: Deploy
        run: |
          ssh -i ~/.ssh/deploy_key ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_IP }} \
            "cd /var/www/myapp && git pull origin main && npm install --production && pm2 reload myapp"

Step 5 — Push and Watch It Run

Push a commit to main and check the Actions tab in your repository to watch the pipeline execute.

The needs: Keyword

needs: test ensures the deploy job only runs if the test job succeeds — a critical safety gate preventing broken code from reaching production.

Adding a Build Step (For Compiled/Bundled Apps)

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm install
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/

Deploying with Docker Instead

- name: Build and push Docker image
  run: |
    docker build -t myregistry/myapp:${{ github.sha }} .
    docker push myregistry/myapp:${{ github.sha }}

- name: Deploy
  run: |
    ssh -i ~/.ssh/deploy_key user@server \
      "docker pull myregistry/myapp:${{ github.sha }} && docker compose up -d"

Common Errors

"Host key verification failed" — the ssh-keyscan step wasn't run or the known_hosts file wasn't set up correctly; verify Step 4's SSH setup block.

Deployment succeeds but app doesn't update — check that the deploy commands actually reference the correct application path and process manager command.

Best Practices

  • Always run tests before deployment, and gate deployment on tests passing
  • Use a dedicated deploy key, not your personal SSH key, for automation
  • Restrict the deploy key to only the specific server(s) it needs access to

Continue Reading

Browse more articles in DevOps & CI/CD.

  • github actions, ci/cd pipeline, automated deployment, github actions deploy
  • 0 Utilisateurs l'ont trouvée utile
Cette réponse était-elle pertinente?

Articles connexes

How to Set Up a Self-Hosted GitHub Actions Runner on a VPS

GitHub Actions' hosted runners work well for most projects, but a self-hosted runner on your own...

How to Deploy Automatically on Git Push (Webhook-Based Deployment)

Automating deployment whenever you push to a specific branch removes the manual "SSH in and pull"...

How to Set Up Blue-Green Deployment on a VPS

Blue-green deployment runs two identical production environments — only one live at a time...

How to Use Ansible for Server Configuration Management

Ansible automates server configuration through simple, human-readable YAML files — letting...

Infrastructure as Code Basics: Managing VPS Config with Terraform

Terraform lets you define infrastructure (VPS instances, networks, DNS records) as code, applied...