Server

Cara Konfigurasi Nginx Reverse Proxy untuk Node.js di VPS Ubuntu

Pertama kali saya deploy aplikasi Node.js ke VPS, saya langsung kena masalah klasik: aplikasi jalan di port 3000, tapi user harus ketik :3000 di URL. Enggak profesional banget dong. Solusinya? Nginx reverse proxy. Setup ini bikin aplikasi Node.js kamu bisa diakses lewat port 80/443 standar, plus dapat bonus SSL, caching, dan load balancing.

Saya udah pakai setup ini di berbagai project production, mulai dari API backend sampai full-stack Next.js app. Di tutorial ini, saya share step-by-step yang udah saya pakai berkali-kali tanpa masalah.

Kenapa Pakai Nginx Reverse Proxy?

Sebelum masuk ke konfigurasi, penting buat ngerti kenapa kamu butuh reverse proxy di depan aplikasi Node.js:

  • Port 80/443: User akses domain langsung tanpa port number aneh-aneh
  • SSL Termination: Nginx handle HTTPS, aplikasi tetap jalan di HTTP lokal
  • Security Layer: Nginx filter request jahat sebelum sampai ke aplikasi
  • Static File Serving: Nginx jauh lebih efisien serve file statis dibanding Node.js
  • Load Balancing: Bisa distribute traffic ke beberapa instance aplikasi
  • WebSocket Support: Nginx bisa proxy WebSocket connection untuk real-time apps

Persiapan Awal

Pastikan kamu udah punya:

  • VPS Ubuntu 20.04/22.04/24.04 dengan SSH access
  • Domain yang udah di-pointing ke IP VPS
  • Aplikasi Node.js yang udah jalan di port lokal (misalnya 3000)

Update dulu sistem kamu:

sudo apt update && sudo apt upgrade -y

Step 1 - Install Nginx

Install Nginx dari repository resmi Ubuntu:

sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl status nginx

Kalau muncul output active (running), berarti Nginx udah jalan. Coba buka http://IP_VPS di browser, harusnya muncul halaman welcome Nginx.

Step 2 - Pastikan Aplikasi Node.js Berjalan

Contoh aplikasi Express sederhana di /var/www/myapp/app.js:

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.json({ message: 'Hello from Node.js behind Nginx!' });
});

app.listen(PORT, '127.0.0.1', () => {
  console.log(`Server running on port ${PORT}`);
});

Penting: pastikan aplikasi listen di 127.0.0.1, bukan 0.0.0.0. Ini supaya aplikasi cuma bisa diakses dari localhost, enggak langsung dari internet. Biar Nginx yang handle semua request dari luar.

Supaya aplikasi tetap jalan walau VPS reboot, pakai PM2:

npm install -g pm2
cd /var/www/myapp
pm2 start app.js --name myapp
pm2 startup
pm2 save

Cek apakah aplikasi udah jalan:

curl http://127.0.0.1:3000

Harusnya muncul response JSON dari aplikasi kamu.

Step 3 - Buat Nginx Server Block

Sekarang bikin konfigurasi Nginx untuk domain kamu. Buat file baru:

sudo nano /etc/nginx/sites-available/myapp

Isi dengan konfigurasi ini:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    # Logging
    access_log /var/log/nginx/myapp_access.log;
    error_log /var/log/nginx/myapp_error.log;

    # Proxy ke Node.js
    location / {
        proxy_pass http://127.0.0.1:3000;
        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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 86400;
    }

    # Cache file statis
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf)$ {
        proxy_pass http://127.0.0.1:3000;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

Ganti example.com dengan domain kamu yang sebenarnya.

Aktifkan site dan test konfigurasi:

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Kalau output test is successful, berarti konfigurasi udah benar. Coba akses http://example.com di browser.

Step 4 - Pasang SSL dengan Let's Encrypt

HTTPS wajib hukumnya di tahun 2026. Untungnya ada Let's Encrypt yang gratis. Pakai Certbot:

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d example.com -d www.example.com

Ikuti wizard-nya: masukkan email, setuju terms, pilih redirect HTTP ke HTTPS. Selesai!

Certbot otomatis:

  • Buat SSL certificate
  • Update konfigurasi Nginx
  • Set auto-renewal lewat systemd timer

Cek auto-renewal:

sudo certbot renew --dry-run

Kalau enggak ada error, SSL kamu udah siap dan bakal auto-renew sebelum expired.

Step 5 - Konfigurasi WebSocket

Kalau aplikasi kamu pakai WebSocket (Socket.io misalnya), konfigurasi yang saya tulis di atas udah termasuk support WebSocket lewat header Upgrade dan Connection.

Tapi kalau kamu mau lebih spesifik, tambahkan location khusus:

location /socket.io/ {
    proxy_pass http://127.0.0.1:3000;
    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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_read_timeout 86400;
    proxy_send_timeout 86400;
}

Setting proxy_read_timeout 86400 itu 24 jam, supaya koneksi WebSocket enggak keputus karena timeout. Ini penting banget buat aplikasi chat atau real-time notification yang user buka seharian.

Step 6 - Optimasi Performa

Edit file /etc/nginx/nginx.conf untuk tuning performa. Config default Nginx itu konservatif banget, cocok buat development tapi kurang optimal buat production:

worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 4096;
    multi_accept on;
    use epoll;
}

http {
    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

    # Buffer sizes
    proxy_buffer_size 128k;
    proxy_buffers 4 256k;
    proxy_busy_buffers_size 256k;

    # Client limits
    client_max_body_size 50M;
    client_body_timeout 60s;
    client_header_timeout 60s;

    # Keepalive
    keepalive_timeout 65;
    keepalive_requests 1000;

    include /etc/nginx/sites-enabled/*;
}

Restart Nginx setelah edit:

sudo nginx -t && sudo systemctl restart nginx

Setting worker_processes auto bikin Nginx otomatis pakai semua CPU core yang tersedia. worker_connections 4096 artinya setiap worker bisa handle 4096 koneksi bersamaan. Kalau VPS kamu 4 core, total bisa handle 16384 koneksi sekaligus.

Step 7 - Security Headers

Tambahkan security headers di server block untuk proteksi ekstra:

# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;

Header-header ini cegah clickjacking, MIME sniffing, dan XSS attack. Enggak ada alasan buat enggak pasang ini. Saya pernah kena masalah karena enggak pasang X-Frame-Options - website saya bisa di-embed di iframe orang lain buat phishing.

Kalau kamu pakai API dan butuh CORS, tambahkan juga:

add_header Access-Control-Allow-Origin "https://yourfrontend.com" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;

Step 8 - Rate Limiting

Biar aplikasi kamu enggak kena serangan DDoS atau brute force, pasang rate limiting:

# Di block http (nginx.conf)
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

# Di server block
location /api/ {
    limit_req zone=api burst=20 nodelay;
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Artinya: maksimal 10 request per detik per IP, dengan burst sampai 20 request. Lebih dari itu, user dapat error 503. Ini cukup proteksi buat kebanyakan kasus.

Kamu juga bisa bikin zone terpisah buat login endpoint yang lebih ketat:

limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

location /api/login {
    limit_req zone=login burst=5 nodelay;
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
}

Step 9 - Load Balancing untuk Multiple Instances

Kalau aplikasi kamu udah rame dan butuh horizontal scaling, kamu bisa jalanin beberapa instance Node.js dan pakai Nginx sebagai load balancer:

upstream node_backend {
    least_conn;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    server 127.0.0.1:3003;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://node_backend;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

PM2 bisa handle ini otomatis dengan cluster mode:

pm2 start app.js --name myapp -i max

Flag -i max bikin PM2 spawn satu worker per CPU core. Kalau VPS kamu 4 core, bakal ada 4 instance. Update Nginx upstream sesuai jumlah port yang dipakai PM2.

Ada tiga strategy load balancing yang bisa dipilih:

  • round-robin (default): Request didistribusi secara bergantian ke setiap server
  • least_conn: Request dikirim ke server yang paling sedikit koneksi aktif. Cocok kalau request processing time variatif
  • ip_hash: Request dari IP yang sama selalu dikirim ke server yang sama. Cocok buat session-based apps

Troubleshooting Umum

Beberapa masalah yang sering saya temuin:

  • 502 Bad Gateway: Aplikasi Node.js enggak jalan atau listen di port yang salah. Cek dengan curl http://127.0.0.1:3000
  • 504 Gateway Timeout: Aplikasi terlalu lambat respond. Naikkan proxy_read_timeout
  • 413 Request Entity Too Large: Upload file kegedean. Naikkan client_max_body_size
  • WebSocket connect failed: Pastikan header Upgrade dan Connection udah benar di konfigurasi Nginx
  • SSL certificate error: Pastikan domain udah pointing ke IP VPS sebelum jalankan Certbot
  • Permission denied: Cek ownership folder aplikasi dengan ls -la /var/www/myapp

Kalau ada masalah, selalu cek log Nginx dulu:

# Access log
tail -f /var/log/nginx/myapp_access.log

# Error log
tail -f /var/log/nginx/myapp_error.log

Log ini bakal kasih tau persis apa yang salah. 90% masalah Nginx bisa di-diagnose cuma dari baca error log.

Kesimpulan

Nginx reverse proxy itu standar industri buat deploy aplikasi Node.js di production. Dengan setup di atas, kamu udah punya:

  • Akses lewat domain biasa tanpa port number
  • SSL/HTTPS gratis dari Let's Encrypt
  • WebSocket support untuk real-time features
  • Security headers dan rate limiting
  • Load balancing siap pakai kalau traffic naik
  • Caching file statis buat performa lebih cepat

Semua konfigurasi di atas udah saya test di production dan works dengan baik. Tinggal sesuaikan nama domain dan port sesuai kebutuhan aplikasi kamu. Kalau ada pertanyaan atau masalah, cek error log Nginx dulu - 90% masalah biasanya keliatan di situ.

Satu tips terakhir: setelah deploy, cek konfigurasi kamu dengan tool online seperti SSL Labs (ssllabs.com/ssltest) buat memastikan SSL kamu dapat grade A. Dan jangan lupa backup konfigurasi Nginx kamu secara berkala - sekali setup, biasanya enggak diubah lagi, tapi kalau VPS crash kamu bakal butuh backup-nya.


You may also like


0 Comments


Leave a Reply

Comments with links or spam keywords will be rejected.
Scroll to Top