Reverse proxy PM2 + Nginx: hubungkan aplikasi Node.js ke port 80

Lingkungan ujiKeluarga DebianUbuntu 24.04.5 LTSakun pengguna biasa
Pengoperasian aplikasi Node.js dan reverse proxy sudah diperiksa

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.

🎯 Poin penting
🗂️ Alur permintaan
📂 NginxReverse proxy
📄 CertbotSertifikat HTTPS
📂 PM2Jalankan dan mulai otomatis
📄 Aplikasi Node.js
Menjalankan aplikasi dengan PM2 dan memulainya saat boot
Nginx meneruskan permintaan port 80 ke aplikasi
Prasyarat
ServerUbuntu 24.04 yang sudah selesai pengaturan awalsudo aktif untuk akun pengguna biasaDomain diperlukan untuk HTTPS

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=noninteractive

Jika 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 -y

Setelah 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 nodejs
Setting 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 -v
v26.13.0
npm -v
11.20.0

npm 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 ~/hello

Buat 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');
APP

Aplikasi 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 pm2
added 45 packages in 5s
pm2 -v
[PM2] Spawning PM2 daemon with pm2_home=/home/deploy/.pm2
[PM2] PM2 Successfully daemonized
7.1.2

Saat perintah pm2 dijalankan pertama kali, daemon PM2 ikut berjalan, dan PM2 yang terpasang adalah versi 7.1.2.

🔲 pm2 start

cd ~/hello

Pindah 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/s

online 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 hello
Use --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/s
pm2 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/s

Setelah 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/s

PM2 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.pm2

pm2 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 reboot

Sekitar 2 menit kemudian, sambungkan lagi sebagai deploy dan periksa status aplikasi.

uptime -p
up 2 minutes
pm2 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/s

Dua 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 nginx
Setting 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 -v
nginx 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/hello

Nginx hanya membaca pengaturan yang memiliki tautan di folder sites-enabled.

🔲 nginx -t

sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo systemctl reload nginx

Periksa 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 4
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Sat, 07 Nov 2026 08:09:38 GMT
Content-Length: 16

Setelah 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.

🧭 Permintaan ke aplikasi Node.js dan menjalankan ulang
Diagram penjelasan
🧭 Situasi
Alur permintaan
🌐BrowserPermintaan ke example.com
➜
🧱NginxPort 80, proxy_pass
➜
🟢Aplikasi Node.js127.0.0.1:3000
Pengelolaan proses
⚙️systemdLayanan pm2-deploy
➜
🔁PM2Daftar aplikasi dump.pm2
➜
🟢Aplikasi Node.jshello
Permintaan browser diterima Nginx di port 80, diteruskan ke 127.0.0.1:3000 yang tertulis di proxy_pass, lalu respons aplikasi dikembalikan apa adanya.
Saat proses aplikasi berhenti, PM2 langsung menjalankan aplikasi yang sama lagi. Setelah dihentikan dengan kill -9, pm2 list 3 detik kemudian menunjukkan aplikasi online dengan pid baru.
Saat server boot, systemd menjalankan layanan pm2-deploy, dan PM2 menjalankan aplikasi lagi sesuai daftar yang disimpan dengan pm2 save.

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 --nginx

Pemasangan 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

Jika Nginx tidak bisa tersambung ke alamat aplikasi di proxy_pass, Nginx mengembalikan 502 Bad Gateway. Setelah aplikasi dihentikan dengan pm2 stop hello, permintaan yang sama menghasilkan 502, dan di /var/log/nginx/error.log tertinggal baris [connect() failed (111: Connection refused) while connecting to upstream] beserta alamat yang dituju, http://127.0.0.1:3000/. Mulailah dengan memeriksa di pm2 list apakah aplikasi online, dan apakah port tempat aplikasi menerima permintaan sama dengan alamat proxy_pass. Setelah aplikasi dimulai ulang, permintaan yang sama kembali dengan 200.

PM2 menyimpan keluaran aplikasi sebagai file per nama aplikasi di folder .pm2/logs di bawah folder home akun yang menjalankannya. Saat pm2 logs hello --nostream --lines 5 dijalankan, muncul baris terakhir dari dua file, /home/deploy/.pm2/logs/hello-out.log dan hello-error.log, dan file out berisi permintaan GET / yang dicatat aplikasi. Tanpa --nostream, log baru terus dicetak saat masuk.

Layanan mulai otomatis dihapus dengan pm2 unstartup systemd. Setelah menambah atau menghapus aplikasi, jalankan lagi pm2 save agar saat boot aplikasi berjalan sesuai daftar yang berubah. Saat pm2 startup dijalankan, kedua perintah ini juga ditampilkan di akhir keluaran.

ℹ️ 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.

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Buktikan bahwa Anda manusia: 4   +   10   =