Deploy Aplikasi Node.js di VPS dengan PM2 dan Nginx
Kenapa kombinasi ini
Menjalankan node app.js langsung dari terminal itu rapuh: begitu terminal ditutup atau server reboot, aplikasi ikut mati. PM2 menyelesaikan sisi proses — ia menjaga aplikasi tetap jalan, me-restart saat crash, dan menghidupkannya lagi setelah reboot. Nginx menyelesaikan sisi akses — ia menerima trafik dari internet (port 80/443) lalu meneruskannya ke aplikasi yang berjalan di port internal seperti 3000. Keduanya sudah teruji bertahun-tahun dan tidak butuh panel tambahan.
Asumsi di artikel ini: Anda sudah punya VPS Ubuntu 24.04 dengan akses root atau sudo, dan sebuah domain yang diarahkan (record A) ke IP VPS. Contoh aplikasi memakai port 3000 dan domain app.contoh.com — ganti sesuai punya Anda.
1. Pasang Node.js
Ubuntu 24.04 membawa Node.js 18 di repositori bawaan, tapi versi itu sudah tua untuk banyak proyek modern. Lebih aman memakai Node.js 22 LTS dari NodeSource:
sudo apt update && sudo apt install -y curl curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs node -v && npm -v
Perintah kedua menambahkan repositori NodeSource, lalu perintah ketiga memasang node sekaligus npm. Verifikasi dengan node -v — harus keluar v22.x.
2. Siapkan aplikasi
Masuk ke direktori proyek, misalnya /var/www/app. Contoh minimal dengan modul bawaan Node (tanpa dependency) supaya bisa langsung dicoba:
sudo mkdir -p /var/www/app sudo chown -R "$USER:$USER" /var/www/app cd /var/www/app
// app.js
const http = require('http');
const port = process.env.PORT || 3000;
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('OK dari Node.js\n');
}).listen(port, '127.0.0.1', () => {
console.log(`Jalan di port ${port}`);
});
Perhatikan listen diikat ke 127.0.0.1, bukan 0.0.0.0. Aplikasi tidak perlu terekspos langsung ke internet — hanya Nginx yang boleh meneruskan trafik ke sana. Ini satu baris kecil yang sering dilupakan dan berdampak besar pada keamanan.
Untuk proyek nyata (misalnya Express), langkahnya sama: npm ci atau npm install --omit=dev di direktori proyek, lalu pastikan ada perintah start yang jelas di package.json.
3. Jalankan dengan PM2
Pasang PM2 secara global, lalu buat file ecosystem agar konfigurasinya tersimpan dan bisa diulang:
sudo npm install -g pm2
// ecosystem.config.js
module.exports = {
apps: [{
name: 'app',
script: './app.js',
instances: 1,
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3000,
},
max_memory_restart: '500M',
error_file: './logs/err.log',
out_file: './logs/out.log',
time: true,
}],
};
Lalu jalankan:
cd /var/www/app mkdir -p logs pm2 start ecosystem.config.js pm2 status
pm2 status menampilkan nama, status online, dan pemakaian memori. max_memory_restart adalah pengaman: kalau aplikasi bocor memori sampai 500 MB, PM2 me-restart-nya otomatis.
4. Restart otomatis saat server reboot
Ini langkah yang paling sering terlewat. Tanpa ini, sekali VPS reboot (misalnya setelah update kernel), aplikasi diam-diam mati sampai Anda sadar:
pm2 save pm2 startup systemd
pm2 startup akan mencetak satu perintah sudo env ... — jalankan perintah itu persis seperti yang tampil, karena isinya menyesuaikan user dan path di server Anda. Setelah itu, uji dengan sudo reboot, tunggu server kembali, lalu cek pm2 status. Kalau aplikasi kembali online sendiri, konfigurasi sudah benar.
5. Nginx sebagai reverse proxy
Pasang Nginx dan buat konfigurasi site:
sudo apt install -y nginx
# /etc/nginx/sites-available/app
server {
listen 80;
server_name app.contoh.com;
location / {
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
}
}
Header X-Forwarded-* penting: tanpa itu aplikasi akan mengira semua pengunjung berasal dari IP 127.0.0.1, dan log maupun rate limit jadi tidak berguna. Aktifkan site-nya dan uji konfigurasi sebelum reload:
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx
nginx -t wajib dijalankan sebelum reload — kalau ada salah ketik di konfigurasi, Anda ketahuan sebelum Nginx yang sedang jalan ikut terganggu. Setelah ini, http://app.contoh.com sudah menampilkan aplikasi.
6. HTTPS dengan Certbot (opsional tapi dianjurkan)
Begitu domain sudah mengarah dan Nginx jalan, HTTPS tinggal satu perintah:
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d app.contoh.com
Certbot akan mengubah konfigurasi Nginx secara otomatis dan memasang timer perpanjangan sertifikat. Uji perpanjangannya dengan sudo certbot renew --dry-run. Satu catatan: jangan mengedit blok server hasil Certbot secara sembarangan — bagian yang ditandai "managed by Certbot" akan ditulis ulang saat perpanjangan.
7. Log dan update sehari-hari
Beberapa perintah yang akan sering Anda pakai:
pm2 logs app --lines 100 # lihat 100 baris log terakhir pm2 monit # monitor CPU dan memori interaktif pm2 restart app # restart setelah perbaikan kecil pm2 reload app # reload dengan downtime minimal
Alur update versi baru cukup seperti ini:
cd /var/www/app git pull npm ci --omit=dev pm2 reload ecosystem.config.js
reload (bukan restart) lebih halus karena PM2 menunggu proses lama siap diganti sebelum mematikannya. Untuk log jangka panjang, pasang modul rotasi agar disk tidak penuh oleh log:
pm2 install pm2-logrotate pm2 set pm2-logrotate:max_size 10M pm2 set pm2-logrotate:retain 7
Ini membatasi tiap file log 10 MB dan menyimpan 7 arsip terakhir.
Jebakan yang sering terjadi
Port sudah dipakai. Kalau pm2 start gagal dengan EADDRINUSE, ada proses lain di port 3000. Cari dengan ss -tlnp | grep 3000, matikan proses liarnya, baru start ulang.
Aplikasi jalan tapi domain 502 Bad Gateway. Biasanya aplikasi belum benar-benar jalan (pm2 status menunjukkan errored) atau proxy_pass salah port. Cek pm2 logs dulu, baru konfigurasi Nginx.
Aplikasi mati setelah reboot. Hampir selalu karena pm2 save belum dijalankan setelah pm2 start, atau perintah dari pm2 startup belum dieksekusi.
Permission file. Kalau aplikasi dijalankan sebagai user biasa tapi file proyek milik root (atau sebaliknya), PM2 gagal menulis log. Samakan kepemilikan dengan sudo chown -R $USER:$USER /var/www/app sebelum start.
Checklist penutup
- Node.js 22 terpasang dan
node -vterverifikasi - Aplikasi mengikat 127.0.0.1, bukan 0.0.0.0
pm2 start ecosystem.config.jsberstatus onlinepm2 savedan perintahpm2 startupsudah dijalankan, teruji dengan reboot- Nginx
nginx -tlolos dan site aktif, domain menampilkan aplikasi - HTTPS aktif dan
certbot renew --dry-runberhasil - Log berotasi dan alur update (pull → npm ci → pm2 reload) sudah dicoba sekali
Dengan susunan ini, satu VPS kecil sudah cukup menjalankan aplikasi Node.js produksi yang stabil — tanpa panel, tanpa biaya tambahan, dan dengan alur perawatan yang bisa Anda ulang untuk proyek berikutnya.
Komentar
Posting Komentar