Reverse proxy PM2 + Nginx: hubungkan aplikasi Node.js ke port 80
Di server Ubuntu 24.04, kami memasang susunan reverse proxy Node.js PM2 Nginx: PM2 menjalankan aplikasi, dan Nginx meneruskan permintaan yang masuk ke port 80 ke aplikasi. Kami juga memastikan PM2 menjalankan aplikasi lagi meskipun proses aplikasi dihentikan paksa atau server di-reboot.
Kotak hasil di bawah adalah keluaran perintah yang dijalankan dengan pengguna biasa deploy. Di tempat domain dipakai nilai contoh example.com, dan permintaan dikirim dari dalam server dengan header Host.
1️⃣ Instal Node.js
Node.js dipasang dengan mendaftarkan repositori NodeSource ke apt, dan versinya kami pilih Node.js 26, versi LTS per November 2026.
🔲 NodeSource setup_26.x
export DEBIAN_FRONTEND=noninteractiveJika Anda menetapkan nilai ini lebih dulu, jendela yang menanyakan pengaturan tidak muncul saat pemasangan paket. Opsi -E pada perintah sudo di bawah meneruskan nilai ini juga ke perintah yang berjalan dengan hak root.
curl -fsSL https://deb.nodesource.com/setup_26.x | sudo -E bash -2026-11-07 16:08:16 - Repository configured successfully.
2026-11-07 16:08:16 - To install Node.js, run: apt install nodejs -ySetelah skrip selesai mendaftarkan repositori, Anda bisa memasang Node.js dengan apt seperti paket Ubuntu lainnya.
🔲 apt-get install nodejs
sudo -E apt-get install -y nodejsSetting up libatomic1:amd64 (14.2.0-4ubuntu2~24.04.1) ...
Setting up nodejs (26.13.0-1nodesource1) ...
Processing triggers for libc-bin (2.39-0ubuntu8.9) ...
Processing triggers for man-db (2.12.0-4build2) ...🔲 node -v, npm -v
node -vv26.13.0npm -v11.20.0npm sudah termasuk dalam paket nodejs, jadi tidak perlu dipasang terpisah.
2️⃣ Aplikasi uji Node.js
Untuk melihat apakah PM2 dan Nginx terhubung dengan benar, buat aplikasi uji yang mengembalikan satu baris teks saat menerima permintaan.
🔲 app.js
mkdir -p ~/helloBuat folder hello di bawah folder home Anda, lalu tulis file app.js di dalamnya.
cat > ~/hello/app.js <<'APP'
const http = require('http');
http.createServer((req, res) => {
console.log(req.method, req.url);
res.end('hello from node\n');
}).listen(3000, '127.0.0.1');
APPAplikasi hanya menerima permintaan di port 3000 milik 127.0.0.1, jadi tidak bisa dibuka langsung dari luar server. Nginx akan diatur untuk menerima permintaan dari luar dan meneruskannya ke port ini.
3️⃣ Menjalankan aplikasi dengan PM2 dan mulai otomatis
PM2 adalah alat pengelola proses yang menjalankan aplikasi Node.js di latar belakang dan menjalankannya lagi saat proses aplikasi berhenti. Di bagian ini kami juga mengatur mulai otomatis, yang menjalankan aplikasi lagi saat server boot.
🔲 npm install -g pm2
sudo npm install -g pm2added 45 packages in 5spm2 -v[PM2] Spawning PM2 daemon with pm2_home=/home/deploy/.pm2
[PM2] PM2 Successfully daemonized
7.1.2Saat perintah pm2 dijalankan pertama kali, daemon PM2 ikut berjalan, dan PM2 yang terpasang adalah versi 7.1.2.
🔲 pm2 start
cd ~/helloPindah ke folder tempat app.js berada, lalu jalankan aplikasi dengan PM2.
pm2 start app.js --name hello[PM2] Starting /home/deploy/hello/app.js in fork_mode (1 instance)
[PM2] Done.
┌────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ hello │ default │ N/A │ fork │ 17257 │ 0s │ 0 │ online │ 0% │ 26.3mb │ deploy │ disabled │
└────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘--name adalah nama aplikasi yang tampil di daftar PM2, dan perintah berikutnya menunjuk aplikasi dengan nama ini.
pm2 list┌────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ hello │ default │ N/A │ fork │ 17257 │ 2s │ 0 │ online │ 0% │ 58.5mb │ deploy │ disabled │
└────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
host metrics | cpu: 0% | ram usage: 38.8% | disk: ⇓ 0mb/s ⇑ 0mb/sonline di kolom status berarti aplikasi sedang berjalan, dan kolom ↺ adalah berapa kali PM2 memulai ulang aplikasi.
🔲 curl 127.0.0.1:3000
Saat Anda mengirim permintaan dari dalam server, satu baris teks yang dikembalikan aplikasi muncul apa adanya.
curl -sS http://127.0.0.1:3000/hello from node🔲 pm2 restart
Setelah mengubah kode aplikasi, mulai ulang aplikasi agar perubahan diterapkan.
pm2 restart helloUse --update-env to update environment variables
[PM2] Applying action restartProcessId on app [hello](ids: [ 0 ])
[PM2] [hello](0) ✓
┌────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ hello │ default │ N/A │ fork │ 17306 │ 0s │ 1 │ online │ 0% │ 19.3mb │ deploy │ disabled │
└────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
host metrics | cpu: 0% | ram usage: 38.8% | disk: ⇓ 0mb/s ⇑ 0mb/spm2 list┌────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ hello │ default │ N/A │ fork │ 17306 │ 2s │ 1 │ online │ 0% │ 58.3mb │ deploy │ disabled │
└────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
host metrics | cpu: 0% | ram usage: 38.8% | disk: ⇓ 0mb/s ⇑ 0mb/sSetelah dimulai ulang, pid berubah dari 17257 menjadi 17306 dan kolom ↺ naik menjadi 1.
🔲 kill -9
Situasi proses aplikasi berhenti tiba-tiba bisa dibuat dengan kill -9, dan pm2 pid mencetak nomor proses aplikasi.
kill -9 "$(pm2 pid hello)"Periksa lagi daftar PM2 setelah 3 detik.
pm2 list┌────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ hello │ default │ N/A │ fork │ 17797 │ 3s │ 2 │ online │ 0% │ 58.6mb │ deploy │ disabled │
└────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
host metrics | cpu: 51.2% | ram usage: 35.8% | eth0: ⇓ 1kb/s ⇑ 1kb/s | eth1: ⇓ 19kb/s ⇑ 0mb/s | disk: ⇓ 728kb/s ⇑ 3.1mb/sPM2 sudah menjalankan aplikasi lagi dengan pid baru 17797 dalam status online, dan kolom ↺ sudah naik menjadi 2.
🔲 pm2 save
pm2 save[PM2] Saving current process list...
[PM2] Successfully saved in /home/deploy/.pm2/dump.pm2pm2 save menyimpan daftar aplikasi yang sedang berjalan ke file dump.pm2, dan saat boot PM2 menjalankan aplikasi lagi sesuai daftar ini.
🔲 pm2 startup
Agar PM2 berjalan saat boot, daftarkan PM2 sebagai layanan systemd. Perintah di bawah membuat layanan dengan nama akun saat ini dan folder home-nya.
sudo env PATH="$PATH" pm2 startup systemd -u "$(id -un)" --hp "$HOME"ExecStart=/usr/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/usr/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/usr/lib/node_modules/pm2/bin/pm2 kill
[Install]
WantedBy=multi-user.target
Target path
/etc/systemd/system/pm2-deploy.service
Command list
[ 'systemctl enable pm2-deploy' ]
[PM2] Writing init configuration in /etc/systemd/system/pm2-deploy.service
[PM2] Making script booting at startup...
[PM2] [-] Executing: systemctl enable pm2-deploy...
Created symlink /etc/systemd/system/multi-user.target.wants/pm2-deploy.service → /etc/systemd/system/pm2-deploy.service.
[PM2] [v] Command successfully executed.env PATH adalah bagian yang membuat pm2 yang dijalankan dengan hak root bisa menemukan jalur node milik akun saat ini, sedangkan -u dan --hp adalah akun dan folder home yang dipakai layanan. Baris ExecStart di file layanan adalah pm2 resurrect, yang memulihkan daftar aplikasi tersimpan saat boot.
systemctl status pm2-deploy --no-pager | head -n 5○ pm2-deploy.service - PM2 process manager
Loaded: loaded (/etc/systemd/system/pm2-deploy.service; enabled; preset: enabled)
Active: inactive (dead)
Docs: https://pm2.keymetrics.io/enabled berarti layanan berjalan saat boot. pm2 startup hanya mendaftarkan layanan dan tidak menjalankannya sekarang, sehingga tampil inactive (dead), dan layanan berjalan mulai boot berikutnya.
🔲 pm2 list setelah reboot
sudo systemctl rebootSekitar 2 menit kemudian, sambungkan lagi sebagai deploy dan periksa status aplikasi.
uptime -pup 2 minutespm2 list┌────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ hello │ default │ N/A │ fork │ 976 │ 108s │ 0 │ online │ 0% │ 63.0mb │ deploy │ disabled │
└────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
host metrics | cpu: 0.3% | ram usage: 35.1% | disk: ⇓ 4kb/s ⇑ 4kb/sDua menit setelah server menyala, aplikasi sudah online selama 108 detik: PM2 menjalankan aplikasi lagi bersamaan dengan boot.
4️⃣ Pengaturan reverse proxy Nginx
Karena aplikasi hanya menerima permintaan di 127.0.0.1:3000, permintaan yang masuk ke port 80 diterima Nginx lalu diteruskan ke aplikasi. Susunan seperti ini, ketika server di depan menerima permintaan lalu meneruskannya ke server di belakang, disebut reverse proxy.
🔲 apt-get install nginx
sudo -E apt-get install -y nginxSetting up nginx-common (1.24.0-2ubuntu7.19) ...
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
Setting up nginx (1.24.0-2ubuntu7.19) ...nginx -vnginx version: nginx/1.24.0 (Ubuntu)Nginx dari repositori Ubuntu 24.04 adalah versi 1.24.0, dan saat dipasang langsung didaftarkan untuk berjalan saat boot.
🔲 /etc/nginx/sites-available/hello
Buat file /etc/nginx/sites-available/hello dan isi dengan konten berikut.
server {
listen 80;
server_name 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-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";
}
}proxy_pass adalah alamat aplikasi tujuan permintaan diteruskan. Header Host, X-Real-IP, X-Forwarded-For, dan X-Forwarded-Proto adalah nilai yang diteruskan agar aplikasi tahu domain permintaan asli, IP pengunjung, dan apakah permintaannya http atau https.
proxy_http_version 1.1 serta header Upgrade dan Connection diperlukan untuk meneruskan koneksi WebSocket sampai ke aplikasi. Header Upgrade dan Connection tidak diteruskan ke aplikasi setelah melewati proxy, jadi ditambahkan langsung di pengaturan.
sudo ln -sf /etc/nginx/sites-available/hello /etc/nginx/sites-enabled/helloNginx hanya membaca pengaturan yang memiliki tautan di folder sites-enabled.
🔲 nginx -t
sudo nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulsudo systemctl reload nginxPeriksa dulu sintaks pengaturan dengan nginx -t, lalu jika lolos, terapkan pengaturan baru dengan reload tanpa menghentikan Nginx.
🔲 Permintaan curl dengan header Host
curl -sS -i -H 'Host: example.com' http://127.0.0.1/ | head -n 4HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Sat, 07 Nov 2026 08:09:38 GMT
Content-Length: 16Setelah pengaturan dibaca ulang, permintaan yang dikirim dengan header Host mendapat respons aplikasi. Baris Server di header respons adalah nginx, dan Content-Length 16 sama ukurannya dengan baris hello from node yang dikembalikan aplikasi (16 byte termasuk baris baru). Untuk tersambung dari luar server, port 80 harus terbuka di firewall.
5️⃣ Menerapkan HTTPS dengan Certbot
Dengan plugin Nginx milik Certbot, Anda bisa menerbitkan sertifikat dan mengubah pengaturan Nginx sekaligus. Jalankan perintah di bawah saat domain sudah mengarah ke IP server.
sudo certbot --nginxPemasangan Certbot dan uji perpanjangan otomatis ada di artikel di bawah; perintah penerbitan di artikel itu untuk Apache, jadi ganti hanya langkah penerbitan dengan perintah di atas.
🔢 FAQ & Konten yang Direkomendasikan
Log layanan
Perintah journalctl: cara pakai, log per layanan, dan merapikan ukuran jurnal
Artikel tentang cara membaca log layanan systemd seperti nginx dan pm2-deploy per layanan.
ℹ️ Pemberitahuan Afiliasi
Konten di situs ini berisi tautan afiliasi. Jika pengunjung membeli produk atau layanan melalui tautan tersebut, situs ini menerima komisi dari penjual. Harga yang dibayar pembeli(turun saat ada diskon promo ↓), tidak naik karena hal ini. Harga, diskon, dan informasi stok yang ditampilkan berlaku pada saat penulisan dan bisa berbeda dengan kondisi sebenarnya, jadi pastikan kembali di situs penjual sebelum membeli. Pemilihan dan penilaian produk dibuat berdasarkan standar kami sendiri, dan ada tidaknya komisi tidak memengaruhi urutan maupun isi penilaian.