TeknoTUT

Cara Deploy Next.js ke VPS dengan PM2 dan Nginx

Panduan lengkap cara deploy Next.js ke VPS Ubuntu: install Node.js, jalankan aplikasi dengan PM2, reverse proxy Nginx, hingga HTTPS gratis.

Ditulis oleh 11 menit bacaEnglish
Ilustrasi aplikasi web yang diluncurkan ke server VPS
Daftar Isi

Jika anda adalah seorang web developer, tentu anda sudah tidak asing dengan Next.js. Framework React yang satu ini sangat nyaman dipakai saat development: cukup jalankan npm run dev, dan aplikasi langsung bisa dibuka di browser.

Nah, masalahnya biasanya muncul saat aplikasi sudah jadi dan ingin ditayangkan ke internet. Banyak tutorial langsung mengarahkan ke layanan hosting terkelola. Padahal, jika anda sudah punya VPS, aplikasi Next.js bisa berjalan dengan sangat baik di sana, dengan biaya bulanan yang tetap dan kendali penuh di tangan anda.

Untuk itu kita butuh dua "teman" tambahan: PM2 yang menjaga aplikasi tetap hidup, dan Nginx yang berdiri di depan sebagai reverse proxy sekaligus pengurus HTTPS.

Dalam artikel kali ini, kita akan membahas tuntas cara deploy Next.js ke VPS, mulai dari install Node.js, build aplikasi, menjalankannya dengan PM2, memasang Nginx, mengaktifkan HTTPS gratis dari Let's Encrypt, hingga cara memperbarui aplikasi saat ada kode baru. Mari kita mulai!

Gambaran Arsitektur Deploy Next.js di VPS

Sebelum mengetik perintah, ada baiknya kita pahami dulu apa yang akan dibangun. Alurnya seperti ini:

Pengunjung (browser)
        │  HTTPS, port 443
        ▼
Nginx (reverse proxy + sertifikat SSL)
        │  HTTP, 127.0.0.1:3000
        ▼
Next.js (next start), dijaga oleh PM2

Setiap komponen punya tugas masing-masing:

  • Next.js menjalankan server produksi lewat perintah next start. Server ini hanya mendengarkan di 127.0.0.1 port 3000, sehingga tidak bisa diakses langsung dari internet.
  • PM2 adalah process manager untuk Node.js. Tugasnya menjalankan aplikasi di background, menyalakannya kembali jika crash, dan menghidupkannya otomatis saat VPS reboot.
  • Nginx menerima semua koneksi dari internet di port 80 dan 443, lalu meneruskannya ke Next.js.

Dokumentasi resmi Next.js sendiri menyarankan memakai reverse proxy seperti Nginx di depan server Next.js, alih-alih membukanya langsung ke internet. Reverse proxy menangani hal-hal seperti request yang tidak valid, koneksi lambat, batas ukuran payload, dan rate limiting, sehingga server Next.js bisa fokus me-render halaman.

Mengapa Deploy Next.js ke VPS Sendiri?

Ada beberapa alasan mengapa cara ini menarik:

  • Biaya tetap dan mudah diprediksi: anda membayar sewa VPS per bulan, berapa pun jumlah pengunjungnya.
  • Kendali penuh: versi Node.js, konfigurasi server, lokasi data, semuanya anda yang menentukan.
  • Semua fitur Next.js tetap berjalan: menurut dokumentasi resminya, fitur seperti optimasi gambar (next/image), ISR, dan streaming bekerja saat di-self-host dengan next start.
  • Satu VPS untuk banyak hal: database, API, dan beberapa website bisa tinggal di server yang sama.

Kekurangan yang Perlu Diketahui

Supaya berimbang, cara ini juga punya kekurangan:

  • Anda yang mengurus server: update sistem, keamanan, dan backup menjadi tanggung jawab anda.
  • Tidak ada scaling otomatis: jika pengunjung melonjak, anda harus menaikkan spesifikasi VPS secara manual.
  • Proses build butuh RAM: next build cukup rakus memori, sehingga VPS kecil perlu sedikit trik (dibahas di bagian troubleshooting).

Persiapan

Sebelum memulai, pastikan anda sudah memiliki:

  • VPS dengan Ubuntu 24.04 LTS atau 26.04 LTS. Perintah di artikel ini ditujukan untuk kedua versi tersebut. Untuk RAM, sebaiknya minimal 1 GB, dan 2 GB akan jauh lebih nyaman saat build.
  • User biasa dengan akses sudo dan firewall yang sudah aktif. Jika VPS anda masih baru, ikuti dulu panduan cara mengamankan VPS Linux.
  • Nama domain yang A record-nya sudah diarahkan ke alamat IP VPS. Ini wajib untuk mendapatkan sertifikat HTTPS.
  • Project Next.js di repositori Git (GitHub, GitLab, atau lainnya). Next.js versi 16 membutuhkan Node.js minimal versi 20.9.

Pada contoh di artikel ini, kita memakai domain example.com, alamat IP 203.0.113.10, user budi, dan project bernama nextjs-app. Silakan ganti dengan milik anda sendiri.

Cara Deploy Next.js ke VPS

Langkah #1: Install Node.js di VPS

Login ke VPS anda, lalu pastikan daftar paket dan tool dasar sudah tersedia:

sudo apt update
sudo apt install -y curl git

Versi Node.js di repositori bawaan Ubuntu sering kali tertinggal. Oleh karena itu, kita akan memakai repositori NodeSource untuk mendapatkan versi LTS (Long Term Support). Unduh dan jalankan script penyiapannya dengan perintah berikut:

curl -fsSL https://deb.nodesource.com/setup_lts.x -o nodesource_setup.sh
sudo -E bash nodesource_setup.sh

Setelah repositorinya terdaftar, install Node.js:

sudo apt install -y nodejs

Periksa versi yang terpasang:

node -v
npm -v

Outputnya kira-kira seperti ini:

v26.13.1
11.6.2

Angka pastinya akan berbeda tergantung kapan anda meng-install-nya. Yang penting, versi Node.js harus 20.9 atau lebih baru. Saat artikel ini ditulis, lini LTS yang masih didukung adalah Node.js 22, 24, dan 26.

Cara install Node.js lainnya, termasuk memakai nvm, bisa anda baca di artikel cara install Node.js. Jika memakai nvm, perhatikan bahwa lokasi node berada di folder home user, dan ini berpengaruh pada perintah pm2 startup di Langkah #4.

Langkah #2: Ambil Kode dan Build Aplikasi

Masuk ke folder home, lalu clone repositori project anda:

cd ~
git clone https://github.com/username/nextjs-app.git
cd nextjs-app

Belum punya project dan hanya ingin mencoba? Anda bisa membuat project contoh langsung di VPS dengan perintah npx create-next-app@latest nextjs-app --yes, lalu masuk ke foldernya.

Selanjutnya, install semua dependensi. Perintah npm ci memasang versi paket persis seperti yang tercatat di package-lock.json, sehingga hasilnya sama dengan di komputer anda:

npm ci

Jika aplikasi anda memakai environment variable, buat file .env.production di folder project:

nano .env.production

Isinya menyesuaikan kebutuhan aplikasi anda, misalnya:

DATABASE_URL=postgres://user:[email protected]:5432/namadb
NEXT_PUBLIC_SITE_URL=https://example.com

Simpan file dengan menekan Ctrl+X, lalu Y, dan Enter.

Penting: variabel yang diawali NEXT_PUBLIC_ akan ditanam langsung ke bundle JavaScript saat build. Artinya, jika nilainya diubah, anda harus menjalankan build ulang. Variabel tanpa awalan itu hanya tersedia di sisi server dan tidak pernah dikirim ke browser.

Sekarang build aplikasi untuk produksi:

npm run build

Proses ini memakan waktu beberapa puluh detik hingga beberapa menit. Di akhir, Next.js menampilkan daftar route yang kira-kira seperti ini:

Route (app)
┌ ○ /
├ ○ /_not-found
└ ƒ /products/[id]
 
○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand

Jika daftar tersebut muncul tanpa pesan error, berarti build berhasil dan hasilnya tersimpan di folder .next.

Langkah #3: Jalankan Next.js dengan PM2

Install PM2 secara global dengan perintah berikut:

sudo npm install -g pm2@latest

Kita bisa saja langsung menjalankan pm2 start "npm run start". Namun, cara yang lebih rapi adalah memakai file konfigurasi, supaya semua pengaturan tersimpan di satu tempat. Buat file ecosystem.config.js di folder project:

nano ecosystem.config.js

Isikan konfigurasi berikut:

module.exports = {
  apps: [
    {
      name: "nextjs-app",
      cwd: "/home/budi/nextjs-app",
      script: "node_modules/next/dist/bin/next",
      args: "start -H 127.0.0.1 -p 3000",
      env: {
        NODE_ENV: "production",
      },
      max_memory_restart: "500M",
    },
  ],
};

Penjelasan singkat setiap baris:

  • name: nama aplikasi di PM2, dipakai pada perintah seperti pm2 restart nextjs-app.
  • cwd: folder project. Sesuaikan dengan nama user dan folder anda.
  • script dan args: PM2 menjalankan langsung program next milik project dengan argumen start. Hasilnya sama dengan npm run start, tetapi tanpa proses npm sebagai perantara.
  • -H 127.0.0.1: bagian ini penting. Secara default, next start mendengarkan di 0.0.0.0, alias semua alamat jaringan. Dengan 127.0.0.1, aplikasi hanya bisa diakses dari dalam VPS (oleh Nginx), bukan langsung dari internet lewat port 3000.
  • max_memory_restart: PM2 me-restart aplikasi jika pemakaian memorinya melewati 500 MB. Sesuaikan dengan RAM VPS anda.

Jika package.json project anda berisi "type": "module", beri nama file ini ecosystem.config.cjs agar tetap dibaca sebagai CommonJS.

Jalankan aplikasi dengan perintah berikut:

pm2 start ecosystem.config.js

Lalu periksa statusnya:

pm2 status

Outputnya kurang lebih seperti di bawah ini:

┌────┬─────────────┬──────┬───────┬────────┬─────────┬────────┬──────┬───────────┐
│ id │ name        │ mode │ pid   │ uptime │ restart │ status │ cpu  │ mem       │
├────┼─────────────┼──────┼───────┼────────┼─────────┼────────┼──────┼───────────┤
│ 0  │ nextjs-app  │ fork │ 12345 │ 10s    │ 0       │ online │ 0%   │ 95.0mb    │
└────┴─────────────┴──────┴───────┴────────┴─────────┴────────┴──────┴───────────┘

Jika kolom status bertuliskan online dan angka restart tidak terus bertambah, berarti aplikasi berjalan dengan stabil. Pastikan juga aplikasi benar-benar merespons:

curl -I http://127.0.0.1:3000

Jika baris pertama outputnya HTTP/1.1 200 OK, berarti Next.js sudah melayani request. Bila statusnya errored, lihat penyebabnya dengan pm2 logs nextjs-app.

Langkah #4: Aktifkan PM2 Saat Boot

Saat ini aplikasi sudah berjalan, tetapi akan hilang jika VPS di-reboot. Untuk mengatasinya, minta PM2 membuat startup script:

pm2 startup

PM2 tidak langsung memasangnya, melainkan menampilkan satu perintah yang harus anda salin dan jalankan. Kira-kira seperti ini:

[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u budi --hp /home/budi

Salin perintah yang muncul di terminal anda sendiri (bukan dari contoh di atas, karena path-nya bisa berbeda), lalu jalankan. Setelah itu, simpan daftar proses yang sedang berjalan:

pm2 save

Selesai! Sekarang setiap kali VPS menyala, PM2 akan otomatis menghidupkan kembali semua aplikasi yang tersimpan.

Jika suatu saat anda meng-upgrade versi Node.js, buat ulang startup script-nya: jalankan pm2 unstartup, lalu pm2 startup sekali lagi.

Langkah #5: Pasang Nginx sebagai Reverse Proxy

Install Nginx dengan perintah berikut:

sudo apt install -y nginx

Jika anda memakai firewall UFW, izinkan koneksi HTTP dan HTTPS. Profil Nginx Full membuka port 80 dan 443 sekaligus:

sudo ufw allow 'Nginx Full'

Selanjutnya, buat file konfigurasi untuk website anda:

sudo nano /etc/nginx/sites-available/nextjs-app

Isikan konfigurasi berikut, dan ganti example.com dengan domain anda:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.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;
    }
}

Baris proxy_pass meneruskan semua request ke Next.js. Baris-baris proxy_set_header memastikan Next.js tetap mengetahui domain yang diminta, alamat IP asli pengunjung, dan apakah koneksinya memakai HTTPS.

Aktifkan konfigurasi tersebut dengan membuat symlink ke folder sites-enabled:

sudo ln -s /etc/nginx/sites-available/nextjs-app /etc/nginx/sites-enabled/

Sebelum menerapkannya, periksa dulu apakah ada kesalahan penulisan:

sudo nginx -t

Jika outputnya menampilkan syntax is ok dan test is successful, muat ulang Nginx:

sudo systemctl reload nginx

Sekarang buka http://example.com di browser. Aplikasi Next.js anda seharusnya sudah tampil, walaupun masih tanpa HTTPS.

Memakai streaming atau Suspense? Nginx secara default menampung (buffer) respons sebelum mengirimkannya, sehingga konten yang seharusnya mengalir bertahap baru muncul sekaligus di akhir. Dokumentasi Next.js menyarankan mengirim header X-Accel-Buffering: no lewat opsi headers() di next.config.js untuk mematikan buffering tersebut.

Langkah #6: Aktifkan HTTPS dengan Certbot

Sertifikat SSL gratis dari Let's Encrypt bisa dipasang dengan mudah memakai Certbot. Cara yang direkomendasikan situs resmi Certbot adalah meng-install-nya lewat snap:

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot

Lalu minta sertifikat sekaligus biarkan Certbot mengubah konfigurasi Nginx secara otomatis:

sudo certbot --nginx -d example.com -d www.example.com

Anda akan diminta mengisi alamat email dan menyetujui ketentuan layanan. Setelah selesai, Certbot menambahkan pengaturan SSL ke file konfigurasi Nginx tadi dan mengalihkan HTTP ke HTTPS.

Sertifikat Let's Encrypt punya masa berlaku terbatas, tetapi Certbot memperpanjangnya secara otomatis. Uji proses perpanjangan itu dengan perintah berikut:

sudo certbot renew --dry-run

Jika simulasi berjalan tanpa error, berarti perpanjangan otomatis sudah siap bekerja. Buka https://example.com, dan ikon gembok di browser menandakan website anda sudah aman. Keren kan?

Cara Update Aplikasi Setelah Ada Perubahan Kode

Deploy bukan pekerjaan sekali jadi. Setiap kali ada kode baru di repositori, jalankan urutan berikut di folder project:

cd ~/nextjs-app
git pull
npm ci
npm run build
pm2 restart nextjs-app

Agar tidak perlu mengetik ulang, simpan urutan tersebut sebagai script. Buat file deploy.sh di folder project:

#!/usr/bin/env bash
set -e
 
cd ~/nextjs-app
git pull
npm ci
npm run build
pm2 restart nextjs-app

Baris set -e membuat script berhenti jika ada langkah yang gagal, sehingga aplikasi tidak di-restart dengan hasil build yang rusak. Beri izin eksekusi, dan setelah itu deploy cukup dengan satu perintah:

chmod +x deploy.sh
./deploy.sh

Perlu diingat, cara sederhana ini menimpa folder .next selagi aplikasi lama masih berjalan, sehingga pengunjung bisa mengalami gangguan singkat selama build dan restart. Untuk website pribadi atau project kecil, hal ini umumnya tidak menjadi masalah.

Perintah PM2 yang Sering Dipakai

Perintah Fungsi
pm2 status Melihat daftar aplikasi dan statusnya
pm2 logs nextjs-app Melihat log aplikasi secara langsung
pm2 logs nextjs-app --lines 200 Menampilkan 200 baris log terakhir
pm2 restart nextjs-app Me-restart aplikasi
pm2 stop nextjs-app Menghentikan aplikasi
pm2 delete nextjs-app Menghapus aplikasi dari daftar PM2
pm2 monit Memantau CPU dan memori secara real-time
pm2 save Menyimpan daftar proses untuk dihidupkan saat boot

Troubleshooting: Masalah yang Sering Muncul

Muncul 502 Bad Gateway

Pesan ini berarti Nginx berjalan, tetapi tidak bisa menghubungi Next.js. Periksa apakah aplikasi hidup dengan pm2 status, lalu baca log-nya dengan pm2 logs nextjs-app. Pastikan juga port di proxy_pass sama dengan port di ecosystem.config.js.

Build Berhenti dengan Pesan "Killed"

Jika npm run build tiba-tiba berhenti dan hanya menampilkan Killed, hampir pasti VPS kehabisan RAM. Solusi termudah adalah menambahkan swap. Langkahnya bisa anda ikuti di artikel memahami swap memory di Linux. Alternatif lainnya adalah menaikkan RAM VPS.

Perubahan Environment Variable Tidak Terbaca

Ada dua kemungkinan. Jika variabelnya berawalan NEXT_PUBLIC_, anda harus menjalankan npm run build lagi karena nilainya ditanam saat build. Jika variabel server biasa di .env.production, cukup jalankan pm2 restart nextjs-app.

Aplikasi Bisa Dibuka Lewat Port 3000 dari Internet

Artinya Next.js masih mendengarkan di 0.0.0.0. Periksa kembali argumen -H 127.0.0.1 di ecosystem.config.js, lalu jalankan pm2 restart nextjs-app. Jangan pula membuka port 3000 di firewall.

Kesimpulan

Dari artikel ini, kita dapat menyimpulkan bahwa deploy Next.js ke VPS sendiri tidaklah serumit yang dibayangkan. Resepnya terdiri dari tiga komponen: Next.js yang berjalan lewat next start di 127.0.0.1:3000, PM2 yang menjaganya tetap hidup dan menyalakannya saat boot, serta Nginx yang menjadi pintu depan sekaligus mengurus HTTPS bersama Certbot.

Cara ini cocok untuk website pribadi, blog, landing page, hingga aplikasi skala kecil-menengah yang cukup dilayani satu server. Jika anda membutuhkan scaling otomatis atau deploy tanpa downtime sama sekali, barulah layanan terkelola atau setup berbasis container layak dipertimbangkan.

Yang perlu diingat:

  • Selalu jalankan Next.js di 127.0.0.1, dan biarkan hanya Nginx yang menghadap internet.
  • Jalankan pm2 save setiap kali daftar aplikasi berubah.
  • Variabel NEXT_PUBLIC_ membutuhkan build ulang.

Lebih suka pendekatan berbasis container? Silakan simak artikel belajar Docker Compose, atau pakai CapRover jika ingin deploy semudah di platform terkelola.


Semoga artikel ini membantu.

Bacaan Selanjutnya

Artikel lain yang mungkin menarik buatmu.