Ravindra BagaleCourses & study guides मराठी Track your progress

Guides

How to Deploy a Node.js App to EC2 with GitHub Actions

Build Node in GitHub Actions, copy to EC2, systemctl restart, curl /health. Keep the SSH key in CI secrets.

Friends, CI builds the zip, SSH only copies and restarts. Chala mitrano — never store the production private key in the repo.

Quick answer

Hold this vertical picture:

  1. Add /health.
  2. Write deploy workflow.
  3. Copy artifact to EC2.
  4. Restart systemd.
  5. curl health; keep previous release.

Language: English · मराठी · हिंदी

Push to mainWorkflow starts CI buildArtifact ready SCP or rsyncFiles on EC2 systemctl restartApp up curl /healthProve it
Node.js to EC2 path

Why this path

Teams still run Node on one EC2 for small apps. CI must build the same way every push.

Why: Manual SCP drifts and breaks Friday deploys. What: GitHub Actions builds, copies, restarts, curls. How: Workflow + systemd + health check.

Example 1: Local Node health route

Type this:

mkdir -p /tmp/node-ec2 && printf '%s\n' 'const http=require("http");http.createServer((q,r)=>{if(q.url==="/health"){r.writeHead(200);r.end("ok")}else r.end("hi")}).listen(3000)' > /tmp/node-ec2/server.js && node -e "require('fs').accessSync('/tmp/node-ec2/server.js');console.log('server.js ready')"

You will see:

server.js ready

What it means: Tiny /health route — Flipkart-style health checks.

Example 2: Run and curl health

Type this:

cd /tmp/node-ec2 && node server.js & sleep 0.4; curl -s http://127.0.0.1:3000/health; kill %1 2>/dev/null || true

You will see:

ok

What it means: Fix the app locally before you trust CI.

Example 3: Package a tarball

Type this:

cd /tmp/node-ec2 && tar -czf /tmp/app.tgz server.js && tar -tzf /tmp/app.tgz

You will see:

server.js

What it means: CI ships a small artifact list.

Concept 1: Build artifact in CI

npm ci then package only what production needs.

Why: Laptop builds hide missing lockfiles. What: Clean install and a small tarball. How: checkout → npm ci → tar.

Example 3: Package a tarball

Type this:

cd /tmp/node-ec2 && tar -czf /tmp/app.tgz server.js && tar -tzf /tmp/app.tgz

You will see:

server.js

What it means: CI ships a small artifact list.

Example 4: Workflow sketch

Type this:

mkdir -p /tmp/node-ec2/.github/workflows && printf '%s\n' 'name: deploy-ec2' 'on: [push]' 'jobs:' '  deploy:' '    runs-on: ubuntu-latest' '    steps:' '      - uses: actions/checkout@v4' '      - run: tar -czf app.tgz server.js' '      - run: echo SCP_TO_EC2_HERE' > /tmp/node-ec2/.github/workflows/deploy.yml && wc -l /tmp/node-ec2/.github/workflows/deploy.yml

You will see:

9 /tmp/node-ec2/.github/workflows/deploy.yml

What it means: Workflow under .github/workflows; key stays in CI secrets.

Example 10: Secrets stay out of git

Type this:

printf '%s\n' 'ok: store EC2_SSH_KEY only in CI secrets'

You will see:

ok: store EC2_SSH_KEY only in CI secrets

What it means: Amazon/Flipkart runbooks ban committing PEM files.

Concept 2: Copy and restart on EC2

SSH/rsync places files; systemd owns the process.

Why: Killing node by hand forgets reboot recovery. What: Unit file + restart + is-active. How: rsync → systemctl restart.

Example 5: systemd unit sketch

Type this:

printf '%s\n' '[Unit]' 'Description=demo node' '[Service]' 'ExecStart=/usr/bin/node /opt/app/server.js' 'Restart=always' '[Install]' 'WantedBy=multi-user.target' > /tmp/node-app.service && head -3 /tmp/node-app.service

You will see:

[Unit]

What it means: TCS/Capgemini expect systemd so reboot recovers.

Example 6: SSH config pattern

Type this:

printf '%s\n' 'Host app-ec2' '  HostName 203.0.113.10' '  User ec2-user' '  IdentityFile ~/.ssh/app-ec2.pem' > /tmp/ssh-demo && cat /tmp/ssh-demo

You will see:

Host app-ec2

What it means: Dedicated deploy key — never paste PEM into YAML.

Example 7: rsync dry-run style

Type this:

mkdir -p /tmp/ec2-opt-app && rsync -avn /tmp/node-ec2/server.js /tmp/ec2-opt-app/ && ls /tmp/ec2-opt-app

You will see:

server.js

What it means: Drop -n on the real host after you trust the list.

Example 8: Remote restart commands

Type this:

printf '%s\n' 'sudo systemctl restart node-app && sudo systemctl is-active node-app' > /tmp/remote-restart.sh && chmod 750 /tmp/remote-restart.sh && cat /tmp/remote-restart.sh

You will see:

sudo systemctl restart node-app && sudo systemctl is-active node-app

What it means: is-active must print active.

Concept 3: Prove and roll back

Health curl in CI; keep previous release.

Why: Green pipeline with a dead app fools the team. What: curl -fsS and a previous folder. How: health → previous symlink.

Example 9: Health in the job

Type this:

printf '%s\n' 'curl -fsS http://127.0.0.1:3000/health' > /tmp/healthcheck.sh && cat /tmp/healthcheck.sh

You will see:

curl -fsS http://127.0.0.1:3000/health

What it means: -f fails the job on HTTP errors.

Example 11: Rollback folders

Type this:

mkdir -p /tmp/releases && printf 'v1\n' > /tmp/releases/previous && printf 'v2\n' > /tmp/releases/current && cat /tmp/releases/previous /tmp/releases/current

You will see:

v1
v2

What it means: Keep previous release for a fast flip.

Example 12: journalctl hint

Type this:

printf '%s\n' 'journalctl -u node-app -n 50 --no-pager'

You will see:

journalctl -u node-app -n 50 --no-pager

What it means: When health fails, read the unit log first.

Deploy card

1 Build in CI 2 Copy to EC2 3 systemctl restart 4 curl /health 5 Keep previous release

Suppose: Permission denied on SCP

Deploy user needs write on /opt/app and sudo for systemctl.

Suppose: Health fails after restart

journalctl -u node-app -n 50; check PORT and NODE_ENV.

Ravindra Bagale's Tip

At Infosys and Accenture, Node on EC2 usually runs under systemd. Reviewers ask for a health curl after every deploy.

Check yourself (quiz)

Q1. Where is the workflow file?

.github/workflows

Q2. Who owns the process?

systemd unit

Q3. Prove deploy?

curl /health with -f

Q4. Where is the SSH key?

CI secrets, never the repo

Q5. Rollback?

Previous release folder

Q6. Why npm ci?

Lockfile-faithful install

Reading tracking

Mark this guide when you finish. Your browser remembers it on this device.

push → build → copy → restart → curl. Did you understand? Let us try it once more.

Frequently asked questions

Why systemd?

Reboot-safe process manager on EC2.

Why not store the key in YAML?

Repo access would steal production.

OIDC option?

Prefer short-lived roles when the path allows.

What if health fails?

Read journalctl for the unit.

rsync or SCP?

Both work; rsync is nicer for many files.

Rollback?

Point back to the previous folder.