Backend Deployment — EC2 + PM2 + nginx
The backend runs as a Node.js cluster managed by PM2 behind an nginx reverse proxy with Certbot SSL on an Ubuntu EC2 instance.
Server Details
| Setting | Value |
|---|---|
| Monorepo path | /home/ubuntu/my-app |
| PM2 process name | prod-logistech |
| Backend port | 3500 |
| Domain | app.intecoglogistech.com |
| OS | Ubuntu 22.04 |
PM2 Configuration
File: ecosystem.config.cjs (monorepo root)
js
module.exports = {
apps: [{
name: 'prod-logistech',
script: './apps/backend/dist/app.js',
cwd: '/home/ubuntu/my-app',
instances: 'max', // one worker per CPU core
exec_mode: 'cluster', // Node.js cluster mode for load balancing
env: {
NODE_ENV: 'production',
PORT: 3500
}
}]
}instances: 'max' automatically starts one PM2 worker per available CPU core.
Deploy Scripts
Both deploy scripts are defined in the root package.json:
bash
# Build + pm2 reload (zero-downtime, use for all regular deploys)
pnpm deploy:backend
# Build + pm2 start (use on first deploy or when ecosystem.config.cjs changes)
pnpm deploy:backend:freshInternally:
bash
# deploy:backend
pnpm --filter @my-app/shared build \
&& pnpm --filter @my-app/backend build \
&& pm2 reload ecosystem.config.cjs --update-env
# deploy:backend:fresh
pnpm --filter @my-app/shared build \
&& pnpm --filter @my-app/backend build \
&& pm2 start ecosystem.config.cjsWhen to use each
| Command | When to use |
|---|---|
pnpm deploy:backend | Normal code updates (zero-downtime cluster reload) |
pnpm deploy:backend:fresh | First deploy, ecosystem config changed, full restart |
nginx Configuration
Reference file: nginx.conf (monorepo root — deploy to /etc/nginx/sites-available/)
nginx
server {
server_name app.intecoglogistech.com;
location / {
proxy_pass http://127.0.0.1:3500;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/app.intecoglogistech.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.intecoglogistech.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
}
server {
if ($host = app.intecoglogistech.com) {
return 301 https://$host$request_uri;
}
listen 80;
server_name app.intecoglogistech.com;
return 404;
}SSL is managed by Certbot (Let's Encrypt). Certbot auto-renews certificates.
Useful PM2 Commands
bash
# Check process status
pm2 status
# View live logs
pm2 logs prod-logistech
# Reload with zero downtime
pm2 reload prod-logistech
# Stop
pm2 stop prod-logistech
# Delete process from PM2 registry
pm2 delete prod-logistech
# Save current process list for auto-restart on reboot
pm2 save
pm2 startupFirst-Time Server Setup
- Install Node.js 18+, pnpm, PM2, nginx, Certbot
- Clone the repository to
/home/ubuntu/my-app - Create
apps/backend/.envwith all required env vars - Run:bash
pnpm install pnpm deploy:backend:fresh - Configure nginx and obtain SSL cert:bash
sudo certbot --nginx -d app.intecoglogistech.com
See docs/server-setup-ec2.md for the full step-by-step EC2 setup guide.
