Files
homaroma/DEPLOYMENT_GUIDE.md
T

9.4 KiB

คู่มือการติดตั้งโปรเจกต์ใหม่ (New Project Deployment Guide)

DBK Platform operational guide: Substitute tenant-specific domains, paths, credentials, and process names. Any homaroma identifier shown elsewhere in the repository is a legacy or reference-tenant identifier unless this guide explicitly selects it. See docs/PLATFORM_OVERVIEW.md.

เอกสารนี้รวบรวมขั้นตอนการสร้างสภาพแวดล้อม (Environment) และการตั้งค่าระบบสำหรับลูกค้ารายใหม่ (เช่น โปรเจกต์ pkh) โดยอ้างอิงจากโครงสร้างระบบปัจจุบันบนเซิร์ฟเวอร์ kitizone.com

Note

ระบบปัจจุบันใช้ Bare Git Repository ในการรับโค้ดและรัน Deployment Hook (post-receive) โปรเจกต์มี 4 โดเมนย่อย: เว็บไซต์หลัก (Next.js), SPA (React), Admin Panel (React), และ API (Elysia.js)


1. เตรียม Git Repository (Bare Repo)

บน Server ให้สร้างโฟลเดอร์สำหรับรับโค้ด:

# กำหนดชื่อโปรเจกต์
PROJECT_NAME="pkh"

# สร้าง Bare Repo
mkdir -p /home/ti/git/${PROJECT_NAME}.git
cd /home/ti/git/${PROJECT_NAME}.git
git init --bare

2. ขอ SSL Certificate & ตั้งค่า Nginx

เนื่องจากใช้ Nginx ผ่าน Docker เราจะต้องรัน Certbot แบบ Standalone เพื่อขอ Certificate

2.1 ปิด Nginx ชั่วคราว

cd /home/ti/projects/MyNginxMain
docker compose stop nginx

2.2 ขอ SSL ด้วย Certbot

เปลี่ยนชื่อโดเมนให้ตรงกับลูกค้า:

docker compose run --rm certbot certonly --standalone \
  -d ${PROJECT_NAME}.kitizone.com \
  -d spa.${PROJECT_NAME}.kitizone.com \
  -d admin.${PROJECT_NAME}.kitizone.com \
  -d api.${PROJECT_NAME}.kitizone.com

2.3 สร้าง Nginx Config Files

เข้าไปที่ /home/ti/projects/MyNginxMain/nginx/conf.d/ และสร้างไฟล์ .conf สำหรับ 4 โดเมน โดยใช้ admin.pkh.kitizone.com.conf เป็นต้นแบบ:

Important

  • สำหรับเว็บไซต์ (Next.js) และ API: ใช้ proxy_pass http://192.168.1.167:<PORT>;
  • สำหรับ SPA และ Admin: ตั้งค่า root /usr/share/nginx/html/${PROJECT_NAME}/spa; ไว้ที่ ระดับ server block (ห้ามใส่ใน location / เพื่อไม่ให้ติดปัญหา CORS หรือ 404 สำหรับไฟล์ static)

ตัวอย่างโครงสร้าง Nginx สำหรับ Admin/SPA:

server {
    listen 443 ssl;
    server_name admin.pkh.kitizone.com;
    ssl_certificate /etc/letsencrypt/live/admin.pkh.kitizone.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/admin.pkh.kitizone.com/privkey.pem;

    root /usr/share/nginx/html/pkh/admin;

    location / {
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires max;
        log_not_found off;
    }
}

2.4 สตาร์ท Nginx

docker compose up -d nginx

3. สร้าง Database

เข้าไปใน Container ของ Postgres เพื่อสร้างฐานข้อมูลใหม่:

docker exec -it arokro_postgres bash
psql -U postgres -c "CREATE DATABASE ${PROJECT_NAME}db;"
exit

4. เปิด Firewall (UFW) ให้พอร์ตใหม่

กำหนดพอร์ตใหม่สำหรับ Next.js (เช่น 3003) และ Backend API (เช่น 3052)

Warning

หากลืมเปิด Firewall ขั้นตอนนี้ Nginx จะตอบกลับด้วย 504 Gateway Timeout ทันที!

sudo ufw allow 3003/tcp
sudo ufw allow 3052/tcp
sudo ufw reload

5. กำหนดค่า Environment (.env)

สร้างโฟลเดอร์สำหรับเก็บโค้ด (ซึ่งจะถูกโคลนมาจาก Git):

mkdir -p /home/ti/projects/${PROJECT_NAME}-api
mkdir -p /home/ti/projects/${PROJECT_NAME}-website

สร้างไฟล์ .env สำหรับ API ที่ /home/ti/projects/${PROJECT_NAME}-api/apps/backend/.env:

PORT=3052
DATABASE_URL="postgresql://postgres:password@localhost:5132/pkhdb?schema=public"
NODE_ENV=production
APP_URL="https://api.pkh.kitizone.com"
BACKEND_PUBLIC_URL="https://api.pkh.kitizone.com"
CORS_ORIGIN="https://admin.pkh.kitizone.com,https://spa.pkh.kitizone.com,https://pkh.kitizone.com"

Tip

สำคัญมาก: Backend ของระบบ (Bun) จะอ่านไฟล์ .env ในโฟลเดอร์ apps/backend/ เป็นหลัก ดังนั้นต้องระบุ CORS_ORIGIN ให้ครบถ้วนเพื่อไม่ให้หน้าบ้าน (React) ติดปัญหา CORS (Error 404/Failed to load resource)


6. ตั้งค่า Git Hook (post-receive)

นำสคริปต์ post-receive ไปวางที่ /home/ti/git/${PROJECT_NAME}.git/hooks/post-receive

จุดที่ต้องแก้ไขใน Script:

  1. แก้ตัวแปรด้านบนสุด:
    TARGET_BACKEND="/home/ti/projects/pkh-api"
    TARGET_WEBSITE="/home/ti/projects/pkh-website"
    TARGET_SPA="/home/ti/projects/MyNginxMain/nginx/html/pkh/spa"
    TARGET_ADMIN="/home/ti/projects/MyNginxMain/nginx/html/pkh/admin"
    
    PM2_NAME_BACKEND="pkh-backend"
    PM2_NAME_WEBSITE="pkh-website"
    
  2. แก้ไข Port ชั่วคราว (ถ้ามีการ copy ecosystem.config.js จาก homaroma):
    sed -i 's/homaroma/pkh/g' $TARGET_BACKEND/ecosystem.config.js
    sed -i 's/PORT: 3002/PORT: 3003/g' $TARGET_WEBSITE/ecosystem.config.js
    
  3. (สำคัญมาก) เพิ่มคำสั่ง sleep 10 หลังการสตาร์ท Backend:
    echo ">>> Managing PM2 Process: $PM2_NAME_BACKEND..."
    $PM2 startOrReload $TARGET_BACKEND/ecosystem.config.js --only $PM2_NAME_BACKEND --env production --update-env
    echo "✅ PM2 process '$PM2_NAME_BACKEND' is running. Waiting 10s for it to fully start..."
    sleep 10
    
    (ป้องกันปัญหาที่ Next.js Build เริ่มทำงานทันทีและ fetch API พังเพราะ Backend เพิ่งถูก restart ไปหมาดๆ)

ตั้งสิทธิ์การรัน:

chmod +x /home/ti/git/${PROJECT_NAME}.git/hooks/post-receive

7. Deploy โค้ด (จากเครื่องนักพัฒนา)

ที่เครื่องของคุณ (Developer):

# แอดเซิร์ฟเวอร์ใหม่
git remote add pkh ti@kitizone.com:/home/ti/git/pkh.git

# สั่ง Deploy
git push pkh master

รอจนกว่าสคริปต์ post-receive จะจัดการ Build ทั้ง Backend, Website (SSR), Admin, และ SPA จนเสร็จ


8. Seed ฐานข้อมูล (ทำครั้งแรกครั้งเดียว)

หลังจาก Push สำเร็จแล้ว Database จะมีตารางต่างๆ สร้างขึ้นมา แต่ยังไม่มีข้อมูลพื้นฐาน ให้รัน Seed Script:

ssh ti@kitizone.com

# รันคำสั่ง Seed
cd /home/ti/projects/${PROJECT_NAME}-api/apps/backend
export PATH=$PATH:/home/ti/.bun/bin:/home/ti/.nvm/versions/node/v22.17.1/bin
bun run prisma/seed.cjs

ระบบจะสร้าง:

  • เมนูพื้นฐาน (Core Menus)
  • ข้อมูลพื้นฐาน (แบรนด์, หมวดหมู่ - ไม่ seed สินค้า)
  • บัญชี Admin (admin / homaroma123)

สรุปปัญหาที่มักพบ (Troubleshooting)

  1. Next.js Build พัง (504 Gateway Timeout ตอนดึง Sitemap):
    • สาเหตุ: API หรือ Database ดาวน์, หรือลืมเปิดพอร์ต Backend ด้วยคำสั่ง ufw allow
    • แก้ไข: ตรวจสอบพอร์ต UFW ว่าเปิดแล้ว และเช็คสคริปต์ว่ามี sleep 10 ให้ API บูทเสร็จหรือไม่
  2. Admin/SPA พัง (CORS Policy หรือ 404 Assets):
    • สาเหตุ: ลืมระบุ CORS_ORIGIN หรือตั้งค่า root ของ Nginx ไว้ผิดที่ (ผิด Block)
    • แก้ไข: เติม CORS ใน apps/backend/.env แล้ว Restart PM2, และนำ root ออกมาไว้ระดับ server { ... } ใน Nginx