Set Up CI/CD for Your Node.js App Using GitHub Actions and PM2

🚀 Set Up CI/CD for Your Node.js App Using GitHub Actions and PM2

In our previous guide, we manually deployed a Node.js app to a VPS using Nginx and PM2. In this follow-up, we’ll take it one step further and automate the deployment process using GitHub Actions and SSH.

🎯 Why CI/CD Is Important

CI/CD (Continuous Integration and Continuous Deployment) helps streamline your development workflow by automatically running builds, tests, and deployments. Here’s why it’s essential:

  • Speed: Automatically deploy code with every push to main.
  • Consistency: Reduces the chance of human error in deployments.
  • Reliability: Integrates tests to catch issues before production.
  • Productivity: Developers focus on code, not manual deployment steps.
  • Scalability: Works seamlessly as your team or infrastructure grows.

🔐 Step 1: Set Up SSH Access to Your VPS

  1. Generate an SSH key (if you haven’t already):
  2. ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
  3. View and copy your public key:
  4. cat ~/.ssh/id_rsa.pub
  5. Log into your VPS:
  6. ssh your_user@your_server_ip
  7. If .ssh doesn't exist, create it:
  8. mkdir -p ~/.ssh
  9. Edit the authorized_keys file and paste your public key:
  10. nano ~/.ssh/authorized_keys

    Paste the copied key from your local ~/.ssh/id_rsa.pub into this file and save.

  11. Set correct permissions:
  12. 
    chmod 700 ~/.ssh
    chmod 600 ~/.ssh/authorized_keys
      

This ensures your GitHub Actions workflow can SSH into your server securely using the corresponding private key.

🔧 Step 2: Add Secrets to GitHub

Navigate to your GitHub repository → Settings → Secrets and variables → Actions and add the following secrets:

  • VPS_SSH_KEY: Paste the content of your private key (~/.ssh/id_rsa)
  • VPS_HOST: Your server IP (e.g., 123.123.123.123)
  • VPS_USER: Your VPS user (e.g., ubuntu or root)

⚙️ Step 3: GitHub Actions Workflow File

Create a file at .github/workflows/deploy.yml and paste the following content:

name: Deploy to VPS

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts

      - name: Deploy with PM2
        run: |
          ssh -o StrictHostKeyChecking=no ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} << 'EOF'
            echo "🔁 Connected to VPS"

            # Load Node.js environment (optional)
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

            # Navigate to project directory
            cd your-project-directory
            git pull origin main
            npm install
            npx tsc

            pm2 start dist/index.js --name your-project-name || pm2 restart your-project-name
            pm2 save

            echo "✅ Deployment complete!"
          EOF

🚀 Step 4: Trigger Your First CI/CD Deployment

Push any changes to the main branch and watch GitHub Actions handle the rest. It will connect to your server, pull the latest code, rebuild it, and restart the app via PM2. All automated, all hands-off.

✅ Conclusion

You’ve now connected your GitHub repository to your live server using CI/CD. This setup ensures that your application is always up to date without needing to manually SSH every time you push code.

👉 If you missed the initial deployment steps, check out our full guide on How to Deploy an Express.js App on Ubuntu with PM2 and Nginx.

Stay tuned for future posts where we’ll take this CI/CD flow even further — with staging environments, zero-downtime deployments, and automated testing pipelines.

Post a Comment

0 Comments