🏠 Home / Hub

🟢 Node.js Lesson 10 — Docker & Deployment

← Back to Node.js Menu  |  🏠 Hub

1. Dockerfile

# Dockerfile (in project root)
FROM node:20-alpine          # base image — Alpine = small (70MB vs 1GB)

WORKDIR /app                 # working directory inside container

# Copy package files first (cache layer optimization)
COPY package*.json ./
RUN npm ci --only=production # install production deps only

# Copy source code
COPY src/ ./src/
COPY .env.example .env       # example env (real .env via env vars)

# Don't run as root
USER node

EXPOSE 3000

CMD ["node", "src/server.js"]

# .dockerignore (like .gitignore for Docker)
node_modules
.env
.git
*.log
__tests__
*.test.js

2. docker-compose.yml

# docker-compose.yml
version: '3.9'

services:
  app:
    build: .
    ports:
      - "3000:3000"           # host:container
    environment:
      - NODE_ENV=production
      - DB_HOST=postgres       # service name as hostname
      - DB_PORT=5432
      - DB_NAME=myapp
      - DB_USER=admin
      - DB_PASSWORD=secret
      - JWT_SECRET=your_secret_here
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB:       myapp
      POSTGRES_USER:     admin
      POSTGRES_PASSWORD: secret
    volumes:
      - pg_data:/var/lib/postgresql/data  # persist data
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U admin -d myapp"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data

volumes:
  pg_data:
  redis_data:

# Commands:
# docker-compose up -d       ← start all services (detached)
# docker-compose down        ← stop
# docker-compose logs -f app ← stream logs
# docker-compose exec app sh ← enter container shell

3. PM2 — Process Manager

# PM2 = keep Node.js alive, auto-restart on crash, clustering

npm install -g pm2

# Start app
pm2 start src/server.js --name "myapp"

# Cluster mode — use all CPU cores
pm2 start src/server.js --name "myapp" -i max

# ecosystem.config.js (recommended)
module.exports = {
  apps: [{
    name:        'myapp',
    script:      'src/server.js',
    instances:   'max',        // or number like 4
    exec_mode:   'cluster',
    watch:       false,
    max_memory_restart: '500M',
    env: {
      NODE_ENV: 'development',
      PORT:      3000
    },
    env_production: {
      NODE_ENV: 'production',
      PORT:      3000
    }
  }]
};

# Commands
pm2 start ecosystem.config.js --env production
pm2 status          # see all processes
pm2 logs myapp      # tail logs
pm2 restart myapp   # restart
pm2 reload myapp    # zero-downtime reload (cluster)
pm2 stop myapp
pm2 delete myapp
pm2 save            # save process list
pm2 startup         # auto-start on server reboot

4. Nginx Reverse Proxy

# Nginx config: /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name myapp.com www.myapp.com;

    # Redirect HTTP → HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name myapp.com www.myapp.com;

    # SSL certificates (Let's Encrypt)
    ssl_certificate     /etc/letsencrypt/live/myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;

    # Proxy to Node.js
    location / {
        proxy_pass         http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;     # WebSocket
        proxy_set_header   Connection 'upgrade';      # WebSocket
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Static files (serve directly, bypass Node)
    location /uploads/ {
        alias /var/www/myapp/uploads/;
        expires 30d;
    }
}

# SSL with Certbot (Let's Encrypt — FREE)
# sudo certbot --nginx -d myapp.com -d www.myapp.com

5. VPS Deploy Checklist

# 1. Server setup (Ubuntu 22.04)
sudo apt update && sudo apt upgrade -y
sudo apt install nginx certbot python3-certbot-nginx -y

# 2. Install Node.js via nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install 20
nvm use 20

# 3. Install PM2
npm install -g pm2

# 4. Clone & setup app
git clone git@github.com:user/myapp.git /var/www/myapp
cd /var/www/myapp
npm ci --only=production
cp .env.example .env
nano .env   # set production values

# 5. Start with PM2
pm2 start ecosystem.config.js --env production
pm2 save
pm2 startup   # follow the command it outputs

# 6. Setup Nginx + SSL
sudo nano /etc/nginx/sites-available/myapp
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d myapp.com

# Security:
# - Firewall: ufw allow 22,80,443/tcp
# - .env file: chmod 600 .env
# - Never expose DB port to internet
# - Use environment variables, never hardcode secrets
⚠️ .env file ကို git commit မလုပ်ပါနဲ့! Production secrets ကို server environment variables မှာ သတ်မှတ်

🎉 Node.js Complete!

Intro → Modules → File System → Express → REST API → MySQL → JWT Auth → WebSockets → Testing → Docker & Deploy

🏠 Hub 🟢 Node.js Menu

← Node.js 09  |  🏠 Back to Hub

📌 Study Checklist