DEV Community

Basanta Sapkota
Basanta Sapkota

Posted on

Setting Up CI/CD for Node.js with GitHub Actions

Setting up CI/CD for your Node.js app using GitHub Actions can save time and reduce errors by automating repetitive deployment tasks. In this guide, you’ll learn to configure a workflow that pulls code, installs dependencies, manages SSH securely, and deploys with PM2.

What You’ll Need

  • GitHub Repository: For hosting your Node.js code.
  • VPS: A server with SSH access to deploy your app.
  • Secrets Setup: Add credentials (SSH key, IP, user, and environment variables) in GitHub Secrets for secure access.

GitHub Actions Workflow

Here’s a full YAML configuration with each step explained:

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      # 1. Checkout Code
      - name: Checkout code
        uses: actions/checkout@v3

      # 2. Set Up Node.js
      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      # 3. Install Dependencies
      - name: Install dependencies
        run: npm ci

      # 4. Set Up SSH for Deployment
      - name: Set up SSH key
        uses: webfactory/ssh-agent@v0.8.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      # 5. Add VPS to Known Hosts
      - name: Add VPS to known hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan -H "${{ secrets.VPS_IP }}" >> ~/.ssh/known_hosts

      # 6. Deploy Files to VPS
      - name: Deploy to temporary directory on VPS
        env:
          VPS_USER: ${{ secrets.VPS_USER }}
        run: |
          rsync -avz --delete ./ ${VPS_USER}@${{ secrets.VPS_IP }}:/tmp/node-hello/

      # 7. Move Files to Final Directory on VPS
      - name: Move files to /root/node-hello
        env:
          VPS_USER: ${{ secrets.VPS_USER }}
        run: |
          ssh ${VPS_USER}@${{ secrets.VPS_IP }} "
            sudo rsync -avz /tmp/node-hello/ /root/node-hello/
          "

      # 8. Set Up Environment and Manage PM2
      - name: Configure environment and manage PM2
        env:
          VPS_USER: ${{ secrets.VPS_USER }}
          MONGO_URI: ${{ secrets.MONGO_URI }}
          JWT_SECRET: ${{ secrets.JWT_SECRET }}
          BCRYPT_SALT_ROUNDS: ${{ secrets.BCRYPT_SALT_ROUNDS }}
          PORT: ${{ secrets.PORT }}
          NODE_ENV: 'production'
        run: |
          ssh ${VPS_USER}@${{ secrets.VPS_IP }} "
            sudo bash -c '
            cd /root/node-hello

            # Write environment variables to .env
            cat > .env <<EOL
            MONGO_URI=${MONGO_URI}
            JWT_SECRET=${JWT_SECRET}
            BCRYPT_SALT_ROUNDS=${BCRYPT_SALT_ROUNDS}
            NODE_ENV=${NODE_ENV}
            PORT=${PORT}
            EOL

            # Check for PM2 and start app
            if ! command -v pm2 &> /dev/null; then
              npm install -g pm2
            fi
            pm2 startOrRestart server.js --name \"server\" --update-env
            '
          "

      # 9. Clean Up Known Hosts
      - name: Clean up known hosts
        run: |
          ssh-keygen -R "${{ secrets.VPS_IP }}"
Enter fullscreen mode Exit fullscreen mode

Workflow Breakdown

  1. Checkout Code: Pulls your latest code from the main branch.
  2. Node.js Setup: Sets up Node.js (version 18 or higher) for compatibility with modern libraries.
  3. Install Dependencies: npm ci is preferred over npm install for faster installs and consistency with package-lock.json.
  4. SSH Key Setup: Uses webfactory/ssh-agent to securely handle SSH. This action adds your SSH key to the agent without saving it locally.
  5. Add VPS to Known Hosts: Adds your server’s IP to the SSH known hosts list, avoiding interactive prompts during SSH.
  6. Deploy Files to VPS: Uses rsync to deploy files to a temporary directory on the VPS, ensuring only the latest files are uploaded.
  7. Move Files to Final Directory: Moves files from the temporary to the final directory, requiring root privileges to write to /root/node-hello.
  8. Set Environment and PM2: Writes environment variables to a .env file on the server, then starts or restarts the app using PM2. The startOrRestart command is efficient and reduces downtime.
  9. Clean Up Known Hosts: Removes the VPS IP from known hosts after deployment. This step prevents clutter and mitigates risks from SSH fingerprint changes.

Warning! This is a beginner setup and may not cover all scenarios. We’re open to suggestions and feedback to improve this guide, so feel free to share any ideas or tips you have.

Top comments (0)