Belajar ExpressJS - Deployment (PM2, Docker, Cloud)
Episode 24 of 28

Belajar ExpressJS - Deployment (PM2, Docker, Cloud)

Membawa aplikasi Express ke produksi: mode production dan health check, PM2 cluster mode, Dockerfile multi-stage, reverse proxy nginx, serta strategi deployment ke VPS dan platform cloud.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Selama 23 episode aplikasi kalian hidup di mesin lokal. Episode 24 membawanya ke produksi — dan produksi adalah dunia yang berbeda: proses yang harus dijaga tetap hidup, image yang bisa di-deploy berulang kali, dan reverse proxy yang menangani TLS.

Mengapa episode ini penting? Karena deployment yang baik membuat aplikasi selalu tersedia dan mudah diperbaiki. PM2 menjaga proses tetap hidup dan diskala ke semua CPU; Docker membuat environment identik di mana pun dijalankan; nginx menangani HTTPS dan static yang efisien. Tiga lapis ini adalah pola deployment standar aplikasi Express di 2026.

Mode Production dan Health Check

NODE_ENV=production

Sebelum deploy, pastikan aplikasi berjalan di mode produksi — seluruh kebijakan dari config.js episode 16 bergantung padanya (cookie secure, log level, trust proxy):

Jalankan mode produksi
NODE_ENV=production node src/server.js

Health Check Endpoint

Load balancer, container orchestrator, dan uptime monitor butuh endpoint untuk menanyakan "apakah kamu hidup?":

JSHealth check endpoint
import mongoose from "mongoose"
import { pool } from "../models/pgPool.js"
 
app.get("/health", async (req, res) => {
  const dbUp = mongoose.connection.readyState === 1
 
  res.status(dbUp ? 200 : 503).json({
    status: dbUp ? "ok" : "degraded",
    uptime: process.uptime(),
    db: dbUp ? "connected" : "disconnected",
  })
})

Health check yang baik memeriksa ketergantungan nyata (database, Redis) — bukan hanya "server hidup". Platform deployment memakai respons 200/503 ini untuk memutuskan apakah instance sehat.

PM2: Process Manager

Mengapa PM2

PM2 (Process Manager 2) adalah pengelola proses Node yang sudah teruji: restart otomatis saat crash, cluster mode lintas CPU, dan log terpusat.

Install PM2
npm install -g pm2

Cluster Mode

Jalankan cluster mode
pm2 start src/server.js -i max --name express-api
pm2 save
pm2 startup
  • -i max menjalankan satu instance per CPU core — memanfaatkan seluruh CPU untuk aplikasi Node.
  • pm2 save menyimpan daftar proses; pm2 startup membuat PM2 hidup kembali setelah server reboot.

Konfigurasi Ekosistem

Definisikan di file ecosystem.config.cjs agar konsisten:

JSecosystem.config.cjs
module.exports = {
  apps: [
    {
      name: "express-api",
      script: "src/server.js",
      instances: "max",
      exec_mode: "cluster",
      env: {
        NODE_ENV: "production",
      },
      max_memory_restart: "300M",
    },
  ],
}

max_memory_restart me-restart instance yang bocor memori — pertahanan pertama terhadap memory leak.

Tip

pm2 logs, pm2 status, dan pm2 monit adalah dashboard operasional pertama aplikasi kalian. Jika memakai Docker (di bawah), PM2 masuk ke dalam container; tanpa Docker, PM2 berdiri langsung di VPS. Keduanya sah — pilih sesuai lingkungan.

Dockerfile Multi-Stage

Image yang Kecil dan Aman

Dockerfile multi-stage memisahkan build (dengan tool lengkap) dari runtime (minimal):

Dockerfile multi-stage
FROM node:22-alpine AS base
 
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
 
FROM base AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY src ./src
USER node
EXPOSE 3000
CMD ["node", "src/server.js"]

Empat keputusan penting:

  • npm ci --omit=dev — install hanya dependency produksi dari lockfile yang pasti.
  • Tidak menyalin .env — env disuntikkan saat runtime (platform atau -e), bukan di-commit ke image.
  • USER node — aplikasi berjalan sebagai non-root; container yang root adalah risiko keamanan.
  • Stage terpisah — node_modules dibangun sekali dan disalin, image runtime tetap kecil.

.dockerignore

.dockerignore
node_modules
.git
.env*
uploads

Health Check Docker

Health check di Dockerfile
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -qO- http://localhost:3000/health || exit 1

Orchestrator (Docker, K8s, platform) memakai ini untuk mengganti instance yang tidak sehat.

Reverse Proxy nginx

Mengapa Perlu Proxy

  • TLS/HTTPS — nginx mengelola sertifikat (Let's Encrypt); aplikasi fokus pada logika.
  • Static files — nginx menyajikan aset publik jauh lebih efisien daripada Express.
  • Load balancing — nginx membagi request ke beberapa instance (episode 25).
  • gzip/br — kompresi di lapisan proxy, tanpa beban aplikasi.

Konfigurasi

/etc/nginx/sites-available/express-api
server {
    listen 80;
    server_name api.example.com;
 
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
 
    location /static/ {
        alias /var/www/express-api/public/;
        expires 7d;
        add_header Cache-Control "public";
    }
}

Header Upgrade/Connection penting untuk WebSocket Socket.IO (episode 14) — tanpa itu, koneksi realtime terputus. Karena nginx kini berada di depan aplikasi, aktifkan trust proxy di aplikasi agar req.ip dan secure cookie berperilaku benar (episode 20 dan 25).

Platform Cloud

Opsi-opsi Utama

PlatformModelCocok untuk
VPS (Hetzner/DigitalOcean)Kontrol penuh, PM2/DockerTim yang ingin kontrol total
Render / Fly.ioPaaS, deploy dari gitTim kecil, cepat mulai
Railway / VercelPaaS khusus NodeAPI sederhana
KubernetesOrkestrasi penuhSkala enterprise (episode 25)

Deploy ke PaaS (Contoh Render)

Pengaturan di Render
Build Command:  npm ci --omit=dev
Start Command:  node src/server.js
Environment:    NODE_ENV=production, MONGODB_URI, JWT_SECRET, ...

PaaS menangani TLS, restart, dan health check otomatis — kalian hanya perlu menyuntikkan env vars dan memastikan config.js tervalidasi (episode 16).

Warning

Di platform PaaS, jangan menyalin .env ke dalam proyek. Semua secret diisi lewat panel/platform env vars. Aplikasi yang gagal startup karena JWT_SECRET hilang (validasi config episode 16) justru menandakan konfigurasi platform yang benar — lebih baik gagal cepat daripada berjalan dengan secret kosong.

Common Pitfalls

Port Salah di Platform

PaaS menyuntikkan PORT secara acak. Aplikasi harus memakai process.env.PORT (kita lakukan sejak episode 3) — bukan port hardcoded 3000.

Env Hilang di Image Docker

.env tidak di-copy ke image. Selalu suntikkan saat runtime: docker run -e JWT_SECRET=... atau env platform.

lupa npm ci Bukan npm install

npm install bisa memperbarui lockfile dan menginstall dependency dev. npm ci instal persis dari lockfile — reproduktif dan aman.

Penutup

Episode 24 membawa aplikasi ke produksi: mode NODE_ENV=production dengan health check, PM2 cluster, Dockerfile multi-stage yang kecil dan aman, reverse proxy nginx dengan TLS dan WebSocket, serta peta platform cloud dari VPS hingga PaaS.

Inti yang harus dibawa pulang:

  • Health check memeriksa ketergantungan nyata; platform memakainya untuk keputusan sehat/tidak.
  • PM2: -i max cluster, pm2 save + pm2 startup untuk persistence.
  • Dockerfile multi-stage: npm ci --omit=dev, tanpa .env, USER node.
  • nginx menangani TLS, static, gzip, dan WebSocket headers.
  • PaaS: env diisi platform; validasi config (episode 16) gagal cepat jika ada yang kurang.
  • trust proxy diaktifkan begitu ada proxy/load balancer di depan aplikasi.

Di episode 25 selanjutnya kita akan diskala: scaling & high availability — horizontal scale, load balancer, stateless session, observability, dan load testing. Sampai jumpa di episode 25!

Belajar ExpressJS - Deployment (PM2, Docker, Cloud) | Belajar ExpressJS