|
@@ -0,0 +1,322 @@
|
|
|
|
|
+# Deploy frontend (PM2 + Nginx) dengan backend & database di Docker
|
|
|
|
|
+
|
|
|
|
|
+Panduan ini menjelaskan pola deployment di **VPS**: **PostgreSQL + Payload (Next.js backend)** tetap di **Docker**, sementara **frontend** (aplikasi Next.js terpisah) di-build, dijalankan dengan **PM2**, dan dihadapkan ke internet lewat **Nginx** (HTTPS).
|
|
|
|
|
+
|
|
|
|
|
+> **Catatan:** Repositori frontend diasumsikan **terpisah** dari repositori backend (`hanoman-website-be`). Sesuaikan path dan nama folder dengan proyek Anda.
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 1. Gambaran arsitektur
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+Internet
|
|
|
|
|
+ │
|
|
|
|
|
+ ▼
|
|
|
|
|
+┌──────────────────┐
|
|
|
|
|
+│ Nginx :80 / :443│ (SSL, reverse proxy)
|
|
|
|
|
+└────────┬─────────┘
|
|
|
|
|
+ │
|
|
|
|
|
+ ┌────┴────┐
|
|
|
|
|
+ │ │
|
|
|
|
|
+ ▼ ▼
|
|
|
|
|
+┌────────┐ ┌─────────────────────────────┐
|
|
|
|
|
+│ PM2 │ │ Docker Compose │
|
|
|
|
|
+│ Next │ │ • postgres:5432 │
|
|
|
|
|
+│ FE │ │ • payload → host :3000 │
|
|
|
|
|
+│ :3001 │ │ • volume ./media → /app/media│
|
|
|
|
|
+└────────┘ └─────────────────────────────┘
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+- **Frontend (PM2):** misalnya `http://127.0.0.1:3001` (hanya localhost; Nginx yang memproksi ke domain publik).
|
|
|
|
|
+- **Backend (Docker):** `payload` memetakan **`3000:3000`** — di host, API Payload tersedia di `http://127.0.0.1:3000` (REST di `/api/...`).
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 2. Prasyarat di VPS
|
|
|
|
|
+
|
|
|
|
|
+- OS umumnya **Ubuntu 22.04/24.04 LTS** (instruksi berikut memakai `apt`).
|
|
|
|
|
+- **Docker** + **Docker Compose** plugin sudah terpasang dan service backend + DB sudah jalan dengan `docker compose` (lihat README repositori backend).
|
|
|
|
|
+- **Domain** sudah mengarah (A record) ke IP VPS — misalnya:
|
|
|
|
|
+ - `www.example.com` → frontend
|
|
|
|
|
+ - `api.example.com` → backend Payload (disarankan subdomain terpisah agar jelas dan tidak bentrok route `/api` di Next frontend).
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 3. Bagian A — Pastikan backend Docker berjalan
|
|
|
|
|
+
|
|
|
|
|
+Di mesin VPS, di direktori repositori **backend**:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+cd /path/to/hanoman-website-be
|
|
|
|
|
+docker compose --env-file .env -f docker-compose.yml up -d
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Pastikan:
|
|
|
|
|
+
|
|
|
|
|
+- `.env` berisi `DATABASE_URL`, `PAYLOAD_SECRET`, kredensial Postgres, dll.
|
|
|
|
|
+- Folder **`media/`** di host ter-mount ke container (lihat `docker-compose.yml`) agar upload media tidak hilang.
|
|
|
|
|
+
|
|
|
|
|
+Uji cepat dari VPS:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3000/api/
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Jika backend sehat, Anda akan mendapat respons HTTP (bukan koneksi ditolak).
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 4. Bagian B — Node.js, pnpm/yarn, dan PM2
|
|
|
|
|
+
|
|
|
|
|
+### 4.1 Versi Node
|
|
|
|
|
+
|
|
|
|
|
+Samakan **major** Node dengan yang dipakai proyek (cek `engines` di `package.json` frontend). Contoh memakai Node 22 via **nvm** (disarankan):
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
|
|
|
|
|
+source ~/.bashrc
|
|
|
|
|
+nvm install 22
|
|
|
|
|
+nvm use 22
|
|
|
|
|
+node -v
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4.2 PM2 (global)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+npm install -g pm2
|
|
|
|
|
+# opsional: startup otomatis setelah reboot
|
|
|
|
|
+pm2 startup
|
|
|
|
|
+# jalankan perintah yang di-print oleh pm2 startup (sudo env ...)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 5. Bagian C — Build dan jalankan frontend
|
|
|
|
|
+
|
|
|
|
|
+### 5.1 Kloning dan dependensi
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+sudo mkdir -p /var/www
|
|
|
|
|
+sudo chown $USER:$USER /var/www
|
|
|
|
|
+cd /var/www
|
|
|
|
|
+git clone <URL-REPO-FRONTEND> hanoman-frontend
|
|
|
|
|
+cd hanoman-frontend
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Pasang paket (contoh **pnpm**; sesuaikan jika pakai yarn/npm):
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+corepack enable
|
|
|
|
|
+corepack prepare pnpm@latest --activate
|
|
|
|
|
+pnpm install --frozen-lockfile
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 5.2 Environment production (frontend)
|
|
|
|
|
+
|
|
|
|
|
+Buat file **`.env.production`** (atau `.env` sesuai konvensi Next) di root frontend. Minimal:
|
|
|
|
|
+
|
|
|
|
|
+```env
|
|
|
|
|
+# URL publik backend Payload (tanpa slash di akhir)
|
|
|
|
|
+# Gunakan https://api.example.com jika Nginx sudah memproksi ke :3000
|
|
|
|
|
+NEXT_PUBLIC_PAYLOAD_API_URL=https://api.example.com
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Sesuaikan dengan cara frontend Anda menyusun URL:
|
|
|
|
|
+
|
|
|
|
|
+- Jika kode memakai `NEXT_PUBLIC_PAYLOAD_API_URL + '/api/posts'` → isi **tanpa** `/api` di akhir.
|
|
|
|
|
+- Jika kode memakai `NEXT_PUBLIC_PAYLOAD_API_URL + '/posts'` → isi **dengan** `https://api.example.com/api`.
|
|
|
|
|
+
|
|
|
|
|
+**Build-time:** `NEXT_PUBLIC_*` di-embed saat `next build`; setelah mengubahnya, **harus build ulang**.
|
|
|
|
|
+
|
|
|
|
|
+### 5.3 Build
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+pnpm run build
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 5.4 PM2 — file `ecosystem.config.cjs`
|
|
|
|
|
+
|
|
|
|
|
+Di root frontend (mis. `/var/www/hanoman-frontend`), buat `ecosystem.config.cjs`:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+module.exports = {
|
|
|
|
|
+ apps: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: 'hanoman-fe',
|
|
|
|
|
+ cwd: '/var/www/hanoman-frontend',
|
|
|
|
|
+ script: 'node_modules/next/dist/bin/next',
|
|
|
|
|
+ args: 'start -p 3001 -H 127.0.0.1',
|
|
|
|
|
+ instances: 1,
|
|
|
|
|
+ autorestart: true,
|
|
|
|
|
+ max_memory_restart: '512M',
|
|
|
|
|
+ env: {
|
|
|
|
|
+ NODE_ENV: 'production',
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> Port **3001** dipakai agar tidak bentrok dengan backend di **3000**. Sesuaikan jika Anda memakai port lain.
|
|
|
|
|
+
|
|
|
|
|
+Jalankan:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+cd /var/www/hanoman-frontend
|
|
|
|
|
+pm2 start ecosystem.config.cjs
|
|
|
|
|
+pm2 save
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Uji lokal:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3001/
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 6. Bagian D — Nginx (reverse proxy + HTTPS)
|
|
|
|
|
+
|
|
|
|
|
+### 6.1 Instalasi
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+sudo apt update
|
|
|
|
|
+sudo apt install -y nginx
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 6.2 Dua server block (disarankan)
|
|
|
|
|
+
|
|
|
|
|
+**a) Backend — `api.example.com` → `127.0.0.1:3000`**
|
|
|
|
|
+
|
|
|
|
|
+Buat `/etc/nginx/sites-available/hanoman-api`:
|
|
|
|
|
+
|
|
|
|
|
+```nginx
|
|
|
|
|
+server {
|
|
|
|
|
+ listen 80;
|
|
|
|
|
+ server_name api.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";
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**b) Frontend — `www.example.com` → `127.0.0.1:3001`**
|
|
|
|
|
+
|
|
|
|
|
+Buat `/etc/nginx/sites-available/hanoman-www`:
|
|
|
|
|
+
|
|
|
|
|
+```nginx
|
|
|
|
|
+server {
|
|
|
|
|
+ listen 80;
|
|
|
|
|
+ server_name www.example.com example.com;
|
|
|
|
|
+
|
|
|
|
|
+ location / {
|
|
|
|
|
+ proxy_pass http://127.0.0.1:3001;
|
|
|
|
|
+ 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";
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Aktifkan situs:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+sudo ln -sf /etc/nginx/sites-available/hanoman-api /etc/nginx/sites-enabled/
|
|
|
|
|
+sudo ln -sf /etc/nginx/sites-available/hanoman-www /etc/nginx/sites-enabled/
|
|
|
|
|
+sudo rm -f /etc/nginx/sites-enabled/default
|
|
|
|
|
+sudo nginx -t
|
|
|
|
|
+sudo systemctl reload nginx
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 6.3 SSL (Let’s Encrypt)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+sudo apt install -y certbot python3-certbot-nginx
|
|
|
|
|
+sudo certbot --nginx -d api.example.com -d www.example.com -d example.com
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Certbot akan mengubah blok `listen 443 ssl` dan jadwal renew otomatis.
|
|
|
|
|
+
|
|
|
|
|
+Setelah HTTPS aktif, pastikan **`NEXT_PUBLIC_PAYLOAD_API_URL`** memakai **`https://api.example.com`** lalu **build ulang** frontend dan restart PM2:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+cd /var/www/hanoman-frontend
|
|
|
|
|
+pnpm run build
|
|
|
|
|
+pm2 restart hanoman-fe
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 7. Firewall (opsional tapi disarankan)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+sudo ufw allow OpenSSH
|
|
|
|
|
+sudo ufw allow 'Nginx Full'
|
|
|
|
|
+sudo ufw enable
|
|
|
|
|
+sudo ufw status
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Port **3000** dan **3001** tidak perlu dibuka ke publik jika hanya diakses lewat Nginx di localhost.
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 8. CORS dan form kontak
|
|
|
|
|
+
|
|
|
|
|
+- Backend Payload mengatur **`cors: '*'`** di `payload.config.ts`; untuk API umum biasanya cukup.
|
|
|
|
|
+- Endpoint **`POST /api/contact`** memakai **`FRONTEND_ORIGIN`** — set ke origin frontend production, mis. `https://www.example.com`, agar preflight CORS konsisten.
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 9. Alur update (deploy ulang frontend)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+cd /var/www/hanoman-frontend
|
|
|
|
|
+git pull
|
|
|
|
|
+pnpm install --frozen-lockfile
|
|
|
|
|
+# edit .env.production jika perlu
|
|
|
|
|
+pnpm run build
|
|
|
|
|
+pm2 restart hanoman-fe
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Backend + DB:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+cd /path/to/hanoman-website-be
|
|
|
|
|
+git pull
|
|
|
|
|
+docker compose --env-file .env -f docker-compose.yml up -d --build
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 10. Troubleshooting singkat
|
|
|
|
|
+
|
|
|
|
|
+| Gejala | Hal yang dicek |
|
|
|
|
|
+|--------|----------------|
|
|
|
|
|
+| 502 Bad Gateway ke FE | `pm2 status`, `curl http://127.0.0.1:3001/` |
|
|
|
|
|
+| 502 ke API | `docker compose ps`, `curl http://127.0.0.1:3000/api/` |
|
|
|
|
|
+| Frontend tidak bisa fetch API | `NEXT_PUBLIC_*` salah atau belum rebuild; URL harus **https** setelah Certbot |
|
|
|
|
|
+| Media backend 404 | Volume `./media` di Docker dan isi folder `media/` di host |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 11. Ringkasan port di host
|
|
|
|
|
+
|
|
|
|
|
+| Layanan | Port (localhost) | Publik |
|
|
|
|
|
+|--------|-------------------|--------|
|
|
|
|
|
+| Payload (Docker) | `3000` | Via Nginx `api.example.com` |
|
|
|
|
|
+| Frontend (PM2) | `3001` | Via Nginx `www.example.com` |
|
|
|
|
|
+| PostgreSQL (Docker) | `5432` (hanya jika perlu; jangan expose ke internet tanpa kebutuhan) | — |
|
|
|
|
|
+
|
|
|
|
|
+Dokumen ini hanya menjelaskan **frontend + PM2 + Nginx**; manajemen secret, backup DB, dan hardening server mengikuti kebijakan Anda.
|