Framework & Development

Cara Deploy NestJS di Ubuntu 24.04 LTS

Cara Deploy NestJS di Ubuntu 24.04 LTS
Daftar Isi

NestJS adalah framework Node.js berbasis TypeScript dengan arsitektur modular terinspirasi Angular — memakai decorator, dependency injection, serta pemisahan controller, service, dan module secara eksplisit. Panduan ini menjelaskan langkah deploy aplikasi NestJS di Ubuntu 24.04 LTS, menggunakan paket qVM-2, dengan PM2 sebagai process manager dan Nginx sebagai reverse proxy. Pembahasan mencakup instalasi environment server, kustomisasi controller dan service sebagai studi kasus, build project TypeScript, konfigurasi PM2 agar aplikasi berjalan persisten, konfigurasi Nginx, hingga pemasangan SSL gratis menggunakan Let's Encrypt.

Pengenalan

NestJS dibangun di atas Express (secara default) tapi menambahkan struktur project yang jauh lebih ketat: setiap fitur dipecah menjadi controller (menangani HTTP request), service (berisi business logic), dan module (mengelompokkan controller dan service yang berkaitan), dihubungkan lewat dependency injection. Pendekatan ini membuat NestJS lebih cocok untuk REST API berskala besar dengan banyak kontributor, dibanding Express yang lebih bebas tanpa struktur baku.

Berbeda dari Express yang bisa langsung dijalankan dari file JavaScript, NestJS ditulis dalam TypeScript dan wajib melalui proses build (nest build) yang meng-compile seluruh source code menjadi JavaScript di folder dist/, dengan dist/main.js sebagai entry point. Setelah proses build, hasilnya tetap berupa proses Node.js yang harus berjalan terus-menerus, sehingga arsitektur deployment-nya sama dengan Express, Next.js, maupun Nuxt.js: PM2 menjaga proses tetap hidup, Nginx meneruskan request dari domain publik sebagai reverse proxy.

Ubuntu 24.04 LTS dipilih sebagai basis OS karena mendapat dukungan resmi (security update dan bug fix) hingga April 2029, sehingga sesuai digunakan untuk server aplikasi yang membutuhkan masa pakai jangka panjang. Panduan ini ditujukan untuk VPS atau qVM yang baru saja di-deploy (fresh install) dan belum memiliki konfigurasi tambahan apa pun.

Persyaratan

Sebelum memulai deploy, pastikan hal-hal berikut sudah terpenuhi:

Software

  • Ubuntu 24.04 LTS, kondisi fresh install (belum ada web server/service lain yang bentrok port)
  • Akses root atau user dengan hak sudo
  • Koneksi internet untuk mengunduh paket dari repository Ubuntu, dependensi npm, dan sertifikat SSL
  • SSH client pada sisi lokal untuk remote ke qVM
  • Project NestJS yang akan di-deploy (project baru maupun repository Git yang sudah ada)

Hardware / Spesifikasi VPS qVM

Panduan ini menggunakan paket qVM-2, dengan spesifikasi:

  • vCPU: 1 core
  • RAM: 2 GiB
  • Storage: 50 GiB
  • Domain yang sudah diarahkan (A record) ke IP Publik qVM — digunakan untuk konfigurasi reverse proxy dan penerbitan sertifikat SSL

Proses compile TypeScript pada NestJS sedikit lebih berat dibanding menjalankan Express secara langsung, tapi masih dalam batas wajar untuk qVM-2. Apabila project sudah cukup besar dan proses build terasa lambat, upgrade ke paket qVM dengan vCPU lebih banyak akan mempercepat waktu build.

Tahapan

1. Update dan Upgrade OS Ubuntu 24.04 LTS

Lakukan update dan upgrade pada sistem operasi Ubuntu 24.04 LTS terlebih dahulu, sebelum memulai instalasi service lainnya.

bash
apt update && sudo apt upgrade -y

2. Instalasi Nginx

bash
apt install nginx -y

Aktifkan agar berjalan otomatis saat qVM di-reboot, lalu periksa statusnya:

bash
systemctl enable nginx
systemctl status nginx

SCR-20260816-puxl

Apabila status menunjukkan active (running), Nginx sudah dapat digunakan. Akses http://<IP-qVM> melalui browser untuk memastikan halaman default "Welcome to nginx!" tampil dengan benar.

SCR-20260816-plzz

3. Instalasi Node.js dengan NVM

bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash

Muat ulang shell agar perintah nvm dapat langsung digunakan:

bash
source ~/.bashrc

Instal Node.js versi Active LTS terbaru (saat ini Node.js 24.x) dan jadikan sebagai versi default:

bash
nvm install --lts
nvm alias default lts/*

Verifikasi versi Node.js dan npm yang terpasang:

bash
node -v
npm -v

NVM menginstal Node.js pada direktori home milik user yang menjalankan perintah di atas. Pastikan seluruh tahapan berikutnya — instalasi PM2, deploy project, hingga pm2 startup — dilakukan dengan user yang sama.

4. Instalasi PM2

bash
npm install -g pm2

Verifikasi instalasi:

bash
pm2 -v

5. Deploy Project NestJS

Instal Nest CLI secara global, lalu buat project baru:

bash
npm install -g @nestjs/cli
mkdir -p /var/www
cd /var/www
nest new nestjs-app

SCR-20260816-pwko

Saat prompt package manager muncul, pilih npm supaya konsisten dengan perintah pada tahap berikutnya. Apabila project sudah ada di repository Git, gunakan git clone diikuti npm install di dalam direktori project sebagai gantinya.

Pada qVM dengan RAM terbatas (misalnya qVM-2), proses instalasi dependensi maupun build project dapat memakan memori cukup tinggi. Apabila proses gagal karena kehabisan memori, tambahkan swap sementara sebagai penyangga sebelum menjalankan ulang perintah tersebut.

Atur kepemilikan direktori project:

bash
chown -R $USER:www-data /var/www/nestjs-app

6. Studi Kasus: Kustomisasi Controller

Struktur bawaan NestJS memisahkan app.controller.ts (menangani route) dan app.service.ts (berisi logic). Sebagai studi kasus, ganti keduanya untuk menyajikan landing page HTML sekaligus satu endpoint REST API — sekaligus mendemonstrasikan pola controller-service khas NestJS.

bash
vim /var/www/nestjs-app/src/app.service.ts

Ganti seluruh isinya dengan:

ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getLandingPage(): string {
    const year = new Date().getFullYear();
    return `<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="UTF-8" />
  <title>Landing Page - KB Sequel</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: 'Segoe UI', Arial, sans-serif; background: #0f172a; color: #f1f5f9; line-height: 1.6; }
    .hero { background: linear-gradient(135deg, #4338ca 0%, #6366f1 50%, #22d3ee 100%); padding: 80px 20px; text-align: center; color: #fff; }
    .badge { display: inline-block; background: rgba(255,255,255,0.15); padding: 6px 16px; border-radius: 999px; font-size: 0.85rem; margin-bottom: 20px; letter-spacing: 0.5px; }
    .hero h1 { font-size: 2.5rem; margin-bottom: 16px; }
    .hero p { font-size: 1.1rem; max-width: 560px; margin: 0 auto 32px; opacity: 0.95; }
    .btn { display: inline-block; background: #fff; color: #4338ca; padding: 14px 32px; border-radius: 999px; font-weight: 600; text-decoration: none; }
    section { padding: 60px 20px; max-width: 1000px; margin: 0 auto; }
    h2 { text-align: center; font-size: 1.8rem; margin-bottom: 12px; }
    .subtitle { text-align: center; color: #94a3b8; margin-bottom: 40px; }
    .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 24px; }
    .card { background: #1e293b; padding: 26px; border-radius: 16px; border: 1px solid #334155; }
    .card h3 { margin-bottom: 8px; color: #fff; font-size: 1.05rem; }
    .card p { color: #94a3b8; font-size: 0.9rem; }
    footer { text-align: center; padding: 32px 20px; color: #64748b; font-size: 0.9rem; border-top: 1px solid #1e293b; }
    code { background: #1e293b; padding: 2px 8px; border-radius: 6px; }
  </style>
</head>
<body>
  <section class="hero">
    <span class="badge">KB Sequel &middot; Landing Page Demo</span>
    <h1>Deployment Berhasil</h1>
    <p>Halaman ini adalah contoh landing page NestJS yang berjalan di atas PM2 dan Nginx reverse proxy, pada paket qVM-2.</p>
    <a href="#status" class="btn">Lihat Status &rarr;</a>
  </section>

  <section id="status">
    <h2>Apa yang Sudah Berjalan?</h2>
    <p class="subtitle">Ringkasan komponen yang sudah dikonfigurasi sampai tahap ini</p>
    <div class="grid">
      <div class="card">
        <h3>Node.js Aktif</h3>
        <p>Aplikasi NestJS dijalankan di atas Node.js LTS pada port 3000.</p>
      </div>
      <div class="card">
        <h3>PM2 Terkelola</h3>
        <p>Proses berjalan persisten, auto-restart, dan otomatis aktif kembali setelah reboot.</p>
      </div>
      <div class="card">
        <h3>Nginx Reverse Proxy</h3>
        <p>Permintaan dari domain publik diteruskan Nginx ke aplikasi NestJS.</p>
      </div>
      <div class="card">
        <h3>REST API Modular</h3>
        <p>Struktur controller, service, dan module memisahkan logic dengan rapi. Coba endpoint <code>/api/status</code>.</p>
      </div>
    </div>
  </section>

  <footer>
    <p>Landing page ini adalah contoh deploy NestJS dengan PM2 di atas paket qVM-2.</p>
    <p>&copy; ${year} KB Sequel — Semua hak cipta dilindungi.</p>
  </footer>
</body>
</html>`;
  }

  getStatus() {
    return {
      status: 'ok',
      stack: 'NestJS',
      server: 'qVM-2',
      timestamp: new Date().toISOString(),
    };
  }
}
bash
vim /var/www/nestjs-app/src/app.controller.ts

Ganti seluruh isinya dengan:

ts
import { Controller, Get, Header } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  @Header('Content-Type', 'text/html')
  getLandingPage(): string {
    return this.appService.getLandingPage();
  }

  @Get('api/status')
  getStatus() {
    return this.appService.getStatus();
  }
}

Decorator @Header('Content-Type', 'text/html') membuat route / mengembalikan HTML alih-alih di-serialize sebagai JSON (perilaku default NestJS untuk return value non-string). Route /api/status sengaja dibiarkan mengembalikan object biasa, karena NestJS otomatis meng-serialize-nya menjadi JSON.

7. Build Project NestJS

bash
cd /var/www/nestjs-app
npm run build

SCR-20260816-pxio

Perintah ini menjalankan nest build, meng-compile seluruh source TypeScript di src/ menjadi JavaScript di folder dist/, dengan dist/main.js sebagai entry point yang akan dijalankan PM2.

8. Jalankan Aplikasi dengan PM2

bash
pm2 start dist/main.js --name "nestjs-app"

Periksa status dan log aplikasi:

bash
pm2 status
pm2 logs nestjs-app

SCR-20260816-pxop

9. Konfigurasi PM2 Startup

Agar aplikasi otomatis berjalan kembali setelah qVM reboot, buat PM2 startup script:

bash
pm2 startup systemd

Perintah di atas akan menampilkan satu baris perintah tambahan yang perlu dijalankan sebagai root — salin dan jalankan perintah tersebut sesuai output yang muncul. Setelah itu, simpan daftar proses PM2 yang sedang berjalan:

bash
pm2 save

SCR-20260816-pxwm

10. Konfigurasi Nginx sebagai Reverse Proxy

Nginx berperan sebagai reverse proxy, meneruskan request dari domain publik ke aplikasi NestJS yang berjalan pada port 3000.

bash
vim /etc/nginx/sites-available/nestjs.sequel.web.id.conf

Isi dengan konfigurasi berikut:

text
server {
    listen 80;
    listen [::]:80;
    server_name nestjs.sequel.web.id;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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_cache_bypass $http_upgrade;
    }

    access_log /var/log/nginx/nestjs-app_access.log;
    error_log /var/log/nginx/nestjs-app_error.log;
}

Aktifkan dengan symlink ke sites-enabled, lalu uji dan reload konfigurasi:

bash
ln -s /etc/nginx/sites-available/nestjs.sequel.web.id.conf /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

SCR-20260816-pyey

11. Uji Akses Aplikasi

Pastikan subdomain yang Anda gunakan sudah dipointing ke IP Publik qVM Anda, contohnya seperti gambar di bawah ini.

SCR-20260816-pyol

Akses http://nestjs.sequel.web.id melalui browser — landing page pada tahap 6 akan tampil. Uji juga endpoint API dengan:

SCR-20260816-pytf

bash
curl http://nestjs.sequel.web.id/api/status

SCR-20260816-pyya

Apabila response berupa JSON berisi status: "ok", berarti seluruh stack (Nginx, Node.js, dan PM2) sudah berjalan dengan benar.

12. Konfigurasi SSL dengan Let's Encrypt

bash
apt install certbot python3-certbot-nginx -y
bash
certbot --nginx -d nestjs.sequel.web.id

SCR-20260816-pzfa

Certbot akan meminta email untuk notifikasi perpanjangan, konfirmasi persetujuan term of service, kemudian menawarkan opsi redirect otomatis dari HTTP ke HTTPS — pilih opsi redirect agar seluruh trafik diteruskan melalui HTTPS. Plugin ini secara otomatis mengedit server block yang sudah dibuat pada tahap 10 untuk menambahkan blok listen 443 ssl beserta path sertifikat.

Periksa terlebih dahulu apakah mekanisme perpanjangan (renewal) berjalan dengan normal:

bash
certbot renew --dry-run

Setelah tahap ini, https://nestjs.sequel.web.id sudah dapat diakses dengan koneksi terenkripsi SSL, begitu juga endpoint /api/status.

SCR-20260816-pzjg

SCR-20260816-pzpl

Kesimpulan

Sampai tahap ini, VPS qVM-2 (1 core, 2 GiB RAM, 50 GiB storage) sudah menjalankan aplikasi NestJS hasil compile TypeScript, menyajikan landing page sekaligus REST API modular lewat pola controller-service, dikelola PM2 agar berjalan persisten dan otomatis restart apabila terjadi crash atau server reboot, dengan Nginx sebagai reverse proxy di depannya. Aplikasi telah diamankan dengan SSL gratis dari Let's Encrypt beserta redirect otomatis ke HTTPS. Untuk pengembangan lebih lanjut, langkah yang disarankan adalah memecah fitur ke module terpisah sesuai domain aplikasi, menambahkan DTO dan validation pipe untuk validasi input, menghubungkan API ke database lewat TypeORM atau Prisma, dan menyiapkan proses deployment otomatis (CI/CD) yang menjalankan npm run build sebelum restart PM2.

Mulai Kelola Infrastruktur Cloud Anda

Akun Sequel Anda siap untuk memesan & mengelola layanan cloud.

Bagikan
Apakah artikel ini membantu?