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 }}"
Workflow Breakdown
- Checkout Code: Pulls your latest code from the main branch.
- Node.js Setup: Sets up Node.js (version 18 or higher) for compatibility with modern libraries.
- Install Dependencies:
npm ci
is preferred overnpm install
for faster installs and consistency withpackage-lock.json
. - SSH Key Setup: Uses
webfactory/ssh-agent
to securely handle SSH. This action adds your SSH key to the agent without saving it locally. - Add VPS to Known Hosts: Adds your server’s IP to the SSH known hosts list, avoiding interactive prompts during SSH.
- Deploy Files to VPS: Uses
rsync
to deploy files to a temporary directory on the VPS, ensuring only the latest files are uploaded. - Move Files to Final Directory: Moves files from the temporary to the final directory, requiring root privileges to write to
/root/node-hello
. - Set Environment and PM2: Writes environment variables to a
.env
file on the server, then starts or restarts the app using PM2. ThestartOrRestart
command is efficient and reduces downtime. - 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)