Skip to main content

Command Palette

Search for a command to run...

Implementing Zero-Downtime CI/CD for Node.js Apps on AWS EC2

Guide to Zero-Interruptions Deployment for Node.js on AWS EC2

Updated
4 min read
Implementing Zero-Downtime CI/CD for Node.js Apps on AWS EC2

Deploying code sounds easy — until you’re doing it multiple times a day while keeping your production server stable.

Our Node.js backend powers critical features, so even a broken build or 2–3 minutes of downtime wasn’t acceptable. As our team grew, deployment became risky:

  • Manual SSH deployments were slow

  • Missed steps caused crashes

  • Different machines had different Node versions

  • Rollbacks were painful

  • Hotfixes slowed down because the pipeline wasn’t automated

We needed a bulletproof CI/CD pipeline.

Below is the journey of how we moved from a patchy deployment process to a fully automated CI/CD setup using GitHub Actions + AWS EC2 + PM2.


The Problem

1 — Manual Deployments Became a Bottleneck

Every update required logging into EC2, pulling code, installing dependencies, restarting PM2, and praying we didn’t break something.

During busy days, this became tedious — and errors slipped in.

2 — No Consistency Across Deployments

One laptop used Node 16, another had Node 18.
Some deployments skipped tests.
Some forgot npm install.
Some overwrote .env accidentally.

We were relying on luck, not process.

3 — Zero Rollback Support

If something broke:

  • We scrambled to revert to the previous commit

  • Re-deployed manually

  • Restarted PM2 again

Not fast, not reliable.

We needed automation.


Step 1 — Setting Up GitHub Actions for CI

We began by automating the basics:

  • Install Node

  • Install dependencies

  • Run tests

  • Prepare build artifacts

GitHub Actions became our “CI engine”.

Why GitHub Actions?

  • Close to the repository

  • Easy secrets management

  • Parallel jobs

  • Free for most usage

  • Very simple YAML-based workflows

This ensured every push was validated before deployment.


Step 2 — Automating Deployment to AWS EC2

Next, we automated deployment.

Instead of SSH-ing manually to EC2, GitHub Actions now:

  1. Builds the backend

  2. Uploads the updated code to EC2

  3. Restarts PM2 automatically

  4. Verifies that the server comes back online

We securely stored:

  • EC2 host

  • SSH user

  • Private key

  • Environment variables

in GitHub Secrets, eliminating credential sharing.

This alone removed 90% of deployment friction.


Step 3 — Introducing PM2 for Zero-Downtime Restarts

PM2 became our process manager.

It allowed:

  • App restarts without downtime

  • Crash auto-recovery

  • CPU utilization monitoring

  • Log management

  • Easy rollbacks using saved snapshots

Whenever a deployment happened:

pm2 restart node-app

The app restarted instantly while keeping old connections alive.

Downtime: 0 seconds.


Step 4 — Handling Secure Environment Management

We moved all sensitive configuration from code into:

  • .env file on EC2

  • GitHub Secrets for CI

  • PM2 ecosystem config for runtime variables

This ensured:

  • No secrets in Git

  • Easy environment change without redeploy

  • Safer rollbacks


Step 5 — Improving Deployment Reliability

We refined the pipeline further:

Added health checks after deploy

To ensure the API booted correctly.

Added rollback capability

By keeping previous build folders.

Cleaned old build artifacts

To reduce EC2 disk usage over time.

Added monitoring

Using PM2 logs + CloudWatch.

Small improvements → Big stability gains.


Final Architecture Diagram

                 ┌─────────────────────────┐
                 │     GitHub Actions      │
                 │ (CI: Build & Test Code) │
                 └───────────┬─────────────┘
                             │
                             ▼
     ┌────────────────────────────────────────────────┐
     │        GitHub Actions Deployment Job           │
     │  1️⃣ SCP/SSH to EC2                             │
     │  2️⃣ Upload Build Files                         │
     │  3️⃣ Restart PM2                                │
     └───────────┬───────────────────────────┬────────┘
                 │                           │
     ┌───────────▼────────────┐   ┌──────────▼─────────────┐
     │      AWS EC2 Ubuntu    │   │   GitHub Secrets        │
     │  Node.js + PM2 Runtime │   │  (SSH, Host, Env Keys)  │
     └───────────┬────────────┘   └─────────────────────────┘
                 │
     ┌───────────▼────────────┐
     │   Node.js Application  │
     │ (Zero Downtime via PM2)│
     └────────────────────────┘

Conclusion

Migrating to a CI/CD pipeline wasn’t just a tooling upgrade — it was an operational transformation.

With GitHub Actions + EC2 + PM2, we achieved:

  • Fully automated deployments

  • Zero downtime during restarts

  • Safe and secure environment handling

  • Consistent, reliable build process

  • Faster development cycles

  • No more late-night "quick fixes" breaking production

Today, pushing to main is all it takes for a clean, fast, safe deployment — every single time.