Node.js App #
Node.js memiliki HTTP server built-in, tapi menjalankannya langsung di port 80/443 bukan praktik yang baik. Nginx di depan Node.js memberikan banyak keuntungan: HTTPS termination, static file serving yang efisien, gzip compression, rate limiting, dan kemampuan menjalankan multiple instances di belakang load balancer.
Konfigurasi Dasar #
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
# Header standar untuk Node.js
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Dua baris proxy_http_version 1.1 dan proxy_set_header Connection "" adalah pasangan wajib untuk keepalive ke Node.js. Tanpa ini Nginx menggunakan HTTP/1.0 yang tidak mendukung keepalive — setiap request membuat koneksi TCP baru ke Node.js.
Konfigurasi Production-Ready #
Konfigurasi lengkap dengan semua optimasi yang disarankan:
upstream nodejs_app {
server 127.0.0.1:3000;
keepalive 32;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1024;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=31536000" always;
# File statis — Nginx layani langsung, lebih efisien dari Node.js
location /static/ {
alias /var/www/myapp/public/static/;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location /uploads/ {
alias /var/www/myapp/uploads/;
expires 30d;
access_log off;
}
# Semua request lain ke Node.js
location / {
proxy_pass http://nodejs_app;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
Multiple Instances: Manfaatkan Semua CPU Core #
Node.js berjalan dalam satu thread. Untuk memanfaatkan server multi-core, jalankan beberapa instance Node.js di port berbeda dan load balance dengan Nginx:
upstream nodejs_cluster {
# Satu instance per core (server 4 core = 4 instance)
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3003;
keepalive 64;
}
Atau gunakan PM2 yang bisa mengelola multiple Node.js instances dan menghubungkannya lewat satu Unix socket:
upstream nodejs_pm2 {
server unix:/var/run/myapp.sock;
keepalive 16;
}
location / {
proxy_pass http://nodejs_pm2;
proxy_http_version 1.1;
proxy_set_header Connection "";
# ...
}
Unix socket lebih cepat dari TCP loopback karena menghindari overhead network stack.
Membaca IP Klien yang Benar di Node.js #
Setelah Nginx menambahkan X-Forwarded-For, aplikasi Node.js perlu membacanya dengan benar:
// Express.js — aktifkan trust proxy
const app = express();
app.set('trust proxy', 1); // Trust satu proxy (Nginx)
// Sekarang req.ip akan berisi IP klien asli
app.get('/whoami', (req, res) => {
res.json({ ip: req.ip });
});
Tanpa trust proxy, req.ip di Express selalu mengembalikan IP Nginx (127.0.0.1), bukan IP klien asli.
Deployment Zero-Downtime dengan Nginx #
Saat deploy versi baru Node.js, PM2 bisa melakukan rolling restart sementara Nginx tetap melayani request:
# PM2 akan restart instance satu per satu
# Nginx terus mengirim request ke instance yang masih running
pm2 reload myapp --update-env
# Atau dengan zero-downtime manual:
# 1. Start instance baru di port berbeda
# 2. Update konfigurasi Nginx untuk tambah instance baru
# 3. Reload Nginx
# 4. Matikan instance lama
Nginx mendeteksi instance yang sudah dimatikan melalui max_fails dan otomatis berhenti mengirim request ke sana sambil menunggu instance baru siap.
Ringkasan #
proxy_http_version 1.1+proxy_set_header Connection ""adalah pasangan wajib untuk keepalive ke Node.js — jangan terlewat.- Layani file statis dengan Nginx langsung (bukan lewat Node.js) — jauh lebih efisien untuk CSS, JS, gambar.
- Unix socket (
server unix:/...) lebih cepat dari TCP loopback untuk komunikasi Nginx ↔ Node.js di server yang sama.- Di Express.js, aktifkan
trust proxyagarreq.ipmengembalikan IP klien asli, bukan IP Nginx.- Untuk memanfaatkan multi-core, jalankan satu instance Node.js per core dan load balance dengan upstream block.