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 PM2Setiap komponen punya tugas masing-masing:
- Next.js menjalankan server produksi lewat perintah
next start. Server ini hanya mendengarkan di127.0.0.1port3000, 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 dengannext 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 buildcukup 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 gitVersi 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.shSetelah repositorinya terdaftar, install Node.js:
sudo apt install -y nodejsPeriksa versi yang terpasang:
node -v
npm -vOutputnya kira-kira seperti ini:
v26.13.1
11.6.2Angka 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
nodeberada di folder home user, dan ini berpengaruh pada perintahpm2 startupdi 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-appBelum 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 ciJika aplikasi anda memakai environment variable, buat file .env.production di folder project:
nano .env.productionIsinya menyesuaikan kebutuhan aplikasi anda, misalnya:
DATABASE_URL=postgres://user:[email protected]:5432/namadb
NEXT_PUBLIC_SITE_URL=https://example.comSimpan 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 buildProses 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 demandJika 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@latestKita 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.jsIsikan 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
nextmilik project dengan argumenstart. Hasilnya sama dengannpm run start, tetapi tanpa prosesnpmsebagai perantara. - -H 127.0.0.1: bagian ini penting. Secara default,
next startmendengarkan di0.0.0.0, alias semua alamat jaringan. Dengan127.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.jsonproject anda berisi"type": "module", beri nama file iniecosystem.config.cjsagar tetap dibaca sebagai CommonJS.
Jalankan aplikasi dengan perintah berikut:
pm2 start ecosystem.config.jsLalu periksa statusnya:
pm2 statusOutputnya 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:3000Jika 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 startupPM2 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/budiSalin 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 saveSelesai! 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, lalupm2 startupsekali lagi.
Langkah #5: Pasang Nginx sebagai Reverse Proxy
Install Nginx dengan perintah berikut:
sudo apt install -y nginxJika 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-appIsikan 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 -tJika outputnya menampilkan syntax is ok dan test is successful, muat ulang Nginx:
sudo systemctl reload nginxSekarang 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: nolewat opsiheaders()dinext.config.jsuntuk 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/certbotLalu minta sertifikat sekaligus biarkan Certbot mengubah konfigurasi Nginx secara otomatis:
sudo certbot --nginx -d example.com -d www.example.comAnda 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-runJika 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-appAgar 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-appBaris 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.shPerlu 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 savesetiap 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.
Resources dan Link Berguna
- Dokumentasi Next.js: Self-Hosting
- Dokumentasi PM2: Quick Start
- Petunjuk Certbot untuk Nginx
- Repositori NodeSource
Semoga artikel ini membantu.



