Add standalone artifact deploy workflow

This commit is contained in:
2026-05-21 05:26:13 +07:00
parent 70b34f8cf3
commit 3002ef9b8c
5 changed files with 149 additions and 0 deletions

2
.gitignore vendored
View File

@ -8,3 +8,5 @@ dist
.env.production .env.production
.env.local .env.local
tsconfig.tsbuildinfo tsconfig.tsbuildinfo
.deploy-release
*.tar.gz

View File

@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
IMAGE="${DOCKER_IMAGE:-node:20}"
ARTIFACT_NAME="${ARTIFACT_NAME:-abelbirdnest-release.tar.gz}"
cd "$ROOT_DIR"
docker run --rm \
-v "$ROOT_DIR":/app \
-w /app \
"$IMAGE" \
bash -lc '
set -euo pipefail
npm ci
npx prisma generate
npm run build
rm -rf .deploy-release
mkdir -p .deploy-release
cp -R .next/standalone/. .deploy-release/
mkdir -p .deploy-release/.next
cp -R .next/static .deploy-release/.next/static
cp -R public .deploy-release/public
cp -R prisma .deploy-release/prisma
[ -f .env.production ] && cp .env.production .deploy-release/.env.production || true
tar -czf '"$ARTIFACT_NAME"' -C .deploy-release .
'
echo "Artifact created at $ROOT_DIR/$ARTIFACT_NAME"

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <user@host> [remote_base_dir]"
exit 1
fi
TARGET="$1"
REMOTE_BASE_DIR="${2:-/var/www/abelbirdnest-web}"
ARTIFACT_NAME="${ARTIFACT_NAME:-abelbirdnest-release.tar.gz}"
RELEASE_NAME="${RELEASE_NAME:-$(date +%Y%m%d-%H%M%S)}"
REMOTE_RELEASE_DIR="$REMOTE_BASE_DIR/releases/$RELEASE_NAME"
scp "$ARTIFACT_NAME" "$TARGET:$REMOTE_BASE_DIR/"
ssh "$TARGET" "mkdir -p '$REMOTE_RELEASE_DIR' && tar -xzf '$REMOTE_BASE_DIR/$ARTIFACT_NAME' -C '$REMOTE_RELEASE_DIR' && ln -sfn '$REMOTE_RELEASE_DIR' '$REMOTE_BASE_DIR/current'"
echo "Uploaded to $TARGET:$REMOTE_RELEASE_DIR"

View File

@ -352,6 +352,103 @@ npm run build
sudo systemctl restart abelbirdnest-web sudo systemctl restart abelbirdnest-web
``` ```
## 13. Alternatif Deploy: Build di Lokal, Jalankan di Server
Repo ini sekarang mendukung output Next.js `standalone`, sehingga build bisa dilakukan di lingkungan Linux lokal/container lalu artifact di-upload ke server.
### Kapan jalur ini dipakai
Pakai cara ini jika:
- server production terlalu kecil untuk `next build`
- build sering mati karena RAM habis
- Anda ingin memisahkan proses build dan runtime
### Prasyarat
- build harus dilakukan di Linux, atau container Linux
- versi Node saat build harus sama dengan server
- database migration tetap dijalankan di server
### Script yang disediakan
Build artifact Linux:
```bash
deploy/scripts/build-linux-release.sh
```
Upload artifact ke server:
```bash
deploy/scripts/upload-linux-release.sh
```
### Contoh build artifact di lokal
Pastikan `.env.production` sudah ada di root repo jika ingin ikut dibawa ke artifact.
```bash
./deploy/scripts/build-linux-release.sh
```
Artifact default yang dihasilkan:
```bash
abelbirdnest-release.tar.gz
```
Isi artifact:
- server Next.js standalone
- static assets `.next/static`
- folder `public`
- folder `prisma`
- `.env.production` jika tersedia
### Contoh upload ke server
```bash
./deploy/scripts/upload-linux-release.sh abelbirdnest@server /var/www/abelbirdnest-web
```
Setelah upload, script akan:
- copy artifact ke server
- extract ke `/var/www/abelbirdnest-web/releases/<timestamp>`
- update symlink `/var/www/abelbirdnest-web/current`
### Langkah setelah upload di server
Masuk ke server:
```bash
ssh abelbirdnest@server
cd /var/www/abelbirdnest-web/current
set -a
source .env.production
set +a
npx prisma migrate deploy
```
Untuk menjalankan standalone app secara manual:
```bash
PORT=3007 node server.js
```
Jika memakai `systemd`, `WorkingDirectory` service harus diarahkan ke:
```bash
/var/www/abelbirdnest-web/current
```
dan `ExecStart` menjadi:
```bash
/usr/bin/node server.js
```
Jika branch utama nanti bukan `main`, sesuaikan perintah `git pull`. Jika branch utama nanti bukan `main`, sesuaikan perintah `git pull`.
## 12. Checklist Go-Live ## 12. Checklist Go-Live

View File

@ -8,6 +8,7 @@ const securityHeaders = [
]; ];
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
output: "standalone",
reactStrictMode: true, reactStrictMode: true,
poweredByHeader: false, poweredByHeader: false,
async headers() { async headers() {