สูตรสำเร็จ › Deploy บน Vercel
เอกสาร/สูตรสำเร็จ/Deploy บน Vercel

Deploy บน Vercel ด้วย Postgres และ R2

สิ่งที่จะได้

เว็บ Next.js ที่มี Easy CMS บน Vercel: เนื้อหาอยู่ใน Postgres ที่ host ไว้ ไฟล์อัปโหลดอยู่ใน Cloudflare R2 และมี cron สำหรับการเผยแพร่ตามเวลา ใช้: Next.js, ฐานข้อมูล, อัปโหลด, migration

function แบบ serverless ไม่มีดิสก์ที่อยู่ถาวร SQLite และไฟล์อัปโหลดในเครื่องจึงใช้ไม่ได้ ให้ใช้ Postgres และที่เก็บไฟล์แบบ S3 แทน

1. Postgres

สร้างฐานข้อมูลบน Postgres แบบ host ไว้ที่ไหนก็ได้ (Neon, Supabase, marketplace ของ Vercel…) แล้วคัดลอก connection string

npm
npm install @easy-cms/db-postgres
pnpm
pnpm add @easy-cms/db-postgres
yarn
yarn add @easy-cms/db-postgres
bun
bun add @easy-cms/db-postgres
easy-cms.config.ts
import { postgres } from '@easy-cms/db-postgres'
 
export default defineConfig({
  // …
  // Vercel: ฐานข้อมูลที่ host ไว้ ส่วนเครื่องคุณ: PGlite (Postgres ในโฟลเดอร์) การพัฒนาและ migration
  // จึงใช้ SQL แบบเดียวกับ production
  db: process.env.DATABASE_URL
    ? postgres({ url: process.env.DATABASE_URL, max: 2 }) // pool เล็กๆ ต่อ function instance
    : postgres({ pglite: '.pglite' }),
})

สำหรับ PGlite ตอนพัฒนา: npm install @electric-sql/pglite (create-easy-cms --db postgres ติดตั้งให้แล้ว)

Connection pooler

ใช้ connection string แบบต่อตรงของฐานข้อมูล pooler แบบ transaction mode อาจไม่รองรับ prepared statement ที่ driver ใช้ ถ้าจะเปลี่ยนไปใช้ ให้ทดสอบก่อน

2. Cloudflare R2 สำหรับไฟล์อัปโหลด

สร้าง bucket และ API token (Object Read & Write) ใน Cloudflare แล้ว:

npm
npm install @easy-cms/storage-s3
pnpm
pnpm add @easy-cms/storage-s3
yarn
yarn add @easy-cms/storage-s3
bun
bun add @easy-cms/storage-s3
import { s3Storage } from '@easy-cms/storage-s3'
 
upload: {
  storage: s3Storage({
    bucket: process.env.R2_BUCKET as string,
    region: 'auto',
    endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
    accessKeyId: process.env.R2_ACCESS_KEY_ID,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
  }),
},

ไฟล์จะถูกส่งผ่าน CMS API เว้นแต่คุณตั้ง URL สาธารณะของ bucket (publicUrl) ดู S3, Cloudflare R2 และ MinIO

3. Migration ทุกครั้งที่ deploy

สร้าง migration ในเครื่อง (ใช้ PGlite ไม่ต้องมี DATABASE_URL) แล้ว commit:

npm
npx easy-cms migrate:create init
git add easy-cms/migrations
pnpm
pnpm exec easy-cms migrate:create init
git add easy-cms/migrations
yarn
yarn easy-cms migrate:create init
git add easy-cms/migrations
bun
bunx easy-cms migrate:create init
git add easy-cms/migrations

แล้วรันก่อน build ทุกครั้งใน package.json:

{ "scripts": { "build": "easy-cms migrate && next build" } }

Vercel รัน npm run build ทุกครั้งที่ deploy ฐานข้อมูลจึงถูก migrate ก่อนที่เวอร์ชันใหม่จะรับ request

4. Environment variable

ใน Project Settings → Environment Variables:

ชื่อค่า
EASY_CMS_SECRETค่าสุ่มใหม่: openssl rand -hex 32
DATABASE_URLconnection string ของ Postgres
R2_BUCKET, R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEYจาก Cloudflare
CRON_SECRETค่าสุ่มอีกค่า สำหรับ cron ด้านล่าง

5. Cron สำหรับบทความที่ตั้งเวลาและ webhook ที่ต้องส่งซ้ำ

บน Vercel ไม่มี process ที่ทำงานค้างไว้ ให้ Vercel Cron เรียก endpoint ของงานแทน Vercel ส่ง Authorization: Bearer $CRON_SECRET ซึ่ง Easy CMS ตรวจให้

vercel.json
{
  "crons": [{ "path": "/api/cms/jobs/run", "schedule": "*/5 * * * *" }]
}

บทความที่ตั้งเวลาไว้จะขึ้นเว็บภายในห้านาทีหลังเวลาที่ตั้ง ตรวจดูว่าแพ็กเกจ Vercel ของคุณให้ cron รันถี่แค่ไหน

6. IP ของผู้ใช้สำหรับการจำกัด login

Vercel ตั้ง X-Forwarded-For ให้ ให้เชื่อค่านี้ใน route ของ API:

export const { GET, HEAD, POST, PATCH, PUT, DELETE, OPTIONS } = createRouteHandlers(config, {
  trustProxy: true,
})

ตรวจสอบ

deploy แล้วเปิด https://your-site.vercel.app/admin สร้าง admin คนแรก อัปโหลดรูป (ไฟล์จะไปอยู่ใน bucket) และเผยแพร่บทความ