1. Mengapa Menjalankan Build Langsung di Server VPS Pasti Melumpuhkan Produksi?
Pernahkah kamu berada dalam situasi serba salah di mana kamu ingin membangun aplikasi web modern dengan arsitektur tangguh seperti Next.js dan NestJS, tetapi terbentur oleh realitas anggaran infrastruktur yang hanya mengizinkan kamu menyewa VPS hemat dengan spesifikasi 2 vCPU dan 4 GB RAM?
Pengalaman menegangkan itulah yang pernah saya hadapi ketika pertama kali merilis platform web interaktif ke lingkungan produksi. Di atas kertas, spesifikasi server tersebut sebenarnya sudah lebih dari cukup untuk melayani ribuan pengunjung per jam dalam kondisi normal (runtime traffic).
Namun, mimpi buruk operasional yang sesungguhnya baru dimulai saat satu perintah dieksekusi langsung di terminal VPS: npm run build.
Begitu proses bundling dan kompilasi TypeScript dijalankan di dalam server, serangkaian malapetaka langsung melanda:
- CPU Terkunci di 100%: Siklus prosesor terkuras habis untuk transpilingℹ dan minifyingℹ chunk modul.
- Memori Melompat Menyentuh Batas RAM: Alokasi memori membengkak hingga tidak menyisakan ruang bagi kernel sistem operasi dan background service.
- Koneksi SSH Terputus & Situs Mati: Server mendadak tidak merespons, pengunjung aktif disambut halaman error, dan sesi SSH terputus seketika.
- Kernel Freezeℹ Total (OOM Starvationℹ): Ujung-ujungnya server mengalami hard freezeℹ akibat OOM Killerℹ, dan satu-satunya jalan keluar adalah melakukan hard rebootℹ paksa melalui dashboard kontrol penyedia VPS.
Dari kepanikan tersebut, saya sempat tergoda mencoba jalan pintas: me-build di laptop lokal, lalu mem-push folder .next ke GitHub. Namun cara itu justru menimbulkan malapetaka baru: ukuran repositori Git membengkak ratusan megabyte dalam beberapa hari, rawan kebocoran file secret lokal, serta ketidaksesuaian modul native C++ antara macOS lokal dan server Ubuntu Linux.
Saya sadar, kita butuh paradigma rekayasa yang benar: Jangan pernah membebani server produksi dengan tugas kompilasi kode.
Blueprint Solusi: Pipeline CI/CDℹ "Build di Luar, Jalankan di Dalam" Untuk membebaskan server VPS dari siklus build yang rakus resource, kami merancang arsitektur pipeline otomatis berbasis 5 pilar:
- 1GitHub Actions Cloud Runner: Memindahkan seluruh beban berat proses compile, type-check, dan bundling ke cloud runner GitHub yang bertenaga tanpa menguras 1% pun CPU VPS.
- 2Multi-Stage Dockerfile & Standalone Next.js: Membungkus aplikasi dengan konfigurasi
output: "standalone"yang hanya menyertakan dependensi esensial, memangkas ukuran image dari 1,2 GB menjadi hanya ~118 MB. - 3GitHub Container Registryℹ (ghcr.ioℹ): Menyimpan artefak kontainer secara privat dan aman dengan penomoran tag deterministik berbasis timestamp dan short SHA commit Git.
- 4SSH Rollout & Docker Compose: Server VPS cukup menarik (pull) image siap saji melalui koneksi SSH terenkripsi dan me-rollout kontainer secara mulus via
docker compose. - 5Automated Health Checkℹ & Webhook Alertℹ: Memverifikasi kesiapan aplikasi melalui pollingℹ endpoint
/api/healthsebelum mendeklarasikan deployment sukses, serta mengirim laporan otomatis ke Discord.
Semua Alur: Live Automated Pipeline
Alur end-to-end otomatis dari commit developer hingga rilis produksi
Setiap git push ke branch production secara otomatis memicu orkestrasi cloud GitHub Actions. Beban kompilasi diisolasi di cloud runner, image standalone dipublikasikan ke GHCR, ditarik via SSH ke VPS, diverifikasi via health check, dan dilaporkan ke Discord.
> Webhook event dispatched: push to refs/heads/production > GitHub Actions workflow 'Deploy Frontend to VPS' queued. > Pipeline status: RUNNING (Live automated orchestration).
2. Peta Topologi dan Matriks Komparasi Deployment
Sebelum kita menelaah konfigurasi teknisnya langkah demi langkah, mari kita bandingkan perbedaan kinerja operasional antara deployment manual tradisional dan pipeline CI/CDℹ modern:
3. Komponen Inti Arsitektur Pipeline CI/CD
A. GitHub Actions (Orchestration Engine)
Bertindak sebagai konduktor utama yang dipicu secara otomatis setiap kali ada push ke branch production, atau dijalankan secara manual melalui antarmuka workflow_dispatch dengan opsi runner ubuntu-latest atau self-hosted.
B. Multi-Stage Dockerfile Minimalis
Next.js dikompilasi menggunakan fitur output: "standalone". Hasilnya adalah folder mandiri yang memuat server Node.js minimalis dan modul yang benar-benar digunakan saja. Kontainer dijalankan di bawah akun non-root (nextjs:nodejs) demi standar keamanan tinggi.
C. GitHub Container Registry (ghcr.io)
Artefak kontainer disimpan secara privat di ghcr.io. Setiap versi rilis diberi tag unik komposit YYYYMMDD-HHMMSS-SHA serta tag pointer latest. Fitur automated pruningℹ disetel untuk mempertahankan 3 versi rilis terakhir guna menghemat kuota storage registry.
D. SSH Runner & Docker Compose Rollout
GitHub Runner tersambung ke VPS target melalui SSH terenkripsi menggunakan private key VPS_SSH_KEY, mengeksekusi login GHCRℹ, menarik image baru, dan memperbarui layanan via docker compose up -d --remove-orphans.
E. Automated Health Check & Multi-Channel Alerting
Pipeline melakukan pollingℹ otomatis hingga 6 kali ke endpoint GET /api/health. Jika endpoint mengembalikan status HTTP 200, bot mengirim kartu embed hijau ke Webhook Discord. Jika aplikasi gagal merespons, pipeline dibatalkan dan alert merah dipancarkan seketika.
4. Panduan Implementasi Langkah demi Langkah (Step-by-Step)
Langkah 1: Mengaktifkan Next.js Standalone Mode
Buka file konfigurasi next.config.mjs di proyek kamu dan tambahkan opsi output: "standalone":
Pengaturan ini menginstruksikan Next.js untuk secara cerdas menelusuri seluruh dependensi modul dan menyalinnya ke folder .next/standalone, sehingga kontainer produksi tidak membutuhkan folder node_modules raksasa yang berukuran gigabyte.
Langkah 2: Menyusun Dockerfile Multi-Stage Produksi
Buat file Dockerfile pada direktori root repositori dengan arsitektur 3 tahap (Stage deps, Stage builder, dan Stage runner):
Pastikan kamu juga membuat file .dockerignore agar file lokal tidak bocor ke dalam build image:
Langkah 3: Membuat Endpoint Health Check
Buat route handler di src/app/api/health/route.ts:
Endpoint ini menjadi rujukan otomatis bagi pipeline CI/CDℹ untuk memverifikasi bahwa server Node.js telah menyala sempurna dan siap menerima trafik publik sebelum rilis dinyatakan berhasil.
Langkah 4: Setup Server VPS, Direktori & Autentikasi GHCR
1. Generate SSH Keypair untuk Deployment
Di komputer lokal, buat SSH keypair khusus deployment:
Salin isi public key (~/.ssh/github_actions_vps.pub) ke file ~/.ssh/authorized_keys di server VPS kamu.
2. Buat Direktori Kerja Deployment
Masuk ke terminal VPS kamu dan buat direktori aplikasi:
3. Buat File docker-compose.yml di VPS
Di dalam /var/www/portfolio, buat file docker-compose.yml:
Langkah 5: Menyusun Workflow File GitHub Actions (deploy.yml)
Buat file .github/workflows/deploy.yml pada repositori kamu:
5. Tiga Pelajaran Berharga dari Medan Produksi (War Stories)
A. Bahaya Tag latest vs Strategi Tagging Deterministik
Mengandalkan tag latest sebagai satu-satunya referensi image adalah jebakan berbahaya (anti-pattern). Jika versi rilis baru mengandung bug, kamu akan kesulitan melakukan rollback karena tag latest selalu menunjuk ke commit paling ujung. Dengan pola tag komposit YYYYMMDD-HHMMSS-SHA (seperti 20260927-142010-78ab9c4), setiap image bersifat immutable. Jika rilis baru bermasalah, rollback cukup dilakukan dalam 2 detik dengan mengubah satu variabel IMAGE_TAG di file .env server ke tag versi sebelumnya.
B. Mencegah Kebocoran Secret di Layer Docker Image
Jangan pernah menyuntikkan password database atau secret key ke dalam instruksi ENV di Dockerfile! Setiap baris ENV akan tercatat permanen di metadata layer image dan dapat dibaca siapapun via docker inspect.
- Nilai publik yang dibutuhkan saat kompilasi frontend dipasok melalui
build-args. - Seluruh secret sensitif diinjeksi secara murni saat runtime melalui file environment terisolasi di server VPS.
C. Pembersihan Disk Server Otomatis (Hygiene Maintenance)
Perintah docker image prune -f yang dieksekusi di akhir script SSH secara otomatis membuang image lama yang berstatus dangling tanpa menghapus image rilis aktif. Ini menjaga ruang disk server hemat kamu tetap stabil di bawah 40% kapasitas tanpa perlu pembersihan manual.
6. Hasil Riil di Produksi: Metrik Sebelum vs Sesudah
Penerapan pipeline CI/CDℹ berbasis GHCRℹ dan Docker Compose ini memberikan perbaikan performa operasional yang sangat melegakan bagi tim:
7. Rekomendasi Lapangan untuk Rekayasa DevOps
Keterbatasan budget infrastruktur sering kali memaksa kita menjadi engineer yang lebih disiplin dan kreatif. Dua prinsip mendasar yang selalu kami pegang:
- 1VPS Murah Bukan Alasan untuk Menyerah pada Tech Stack Modern: Next.js dan NestJS tetap dapat hidup berdampingan dengan sangat mulus di VPS 2 vCPU hemat biaya, asalkan arsitektur deployment-nya tepat dan tidak memaksakan proses kompilasi di tempat.
- 2Pemisahan Tanggung Jawab (Separation of Concerns): Mesin produksi bertugas murni melayani pengguna (serving traffic), bukan mengompilasi kode (building artifacts).
Dengan memindahkan beban build ke GitHub Actions dan mengamankan image di GitHub Container Registryℹ, VPS kamu dapat berfokus penuh pada fungsi utamanya: menyajikan aplikasi secara cepat, andal, dan tanpa gangguan bagi seluruh pengunjung.