การ Deploy › Docker
เริ่มต้น
เนื้อหา
Plugins
การดูแลระบบ
การ Deploy
สูตรสำเร็จ
Deploy ด้วย Docker
หน้านี้สอนอะไร
สร้าง container image ของเว็บที่มี Easy CMS แล้วรันด้วย Docker Compose แบบใช้ Postgres ใน container ที่สอง หรือแบบ SQLite บน volume image เดียวกันนี้รันได้บน server หรือแพลตฟอร์มใดก็ได้ที่รัน container
ควรอ่านก่อน: เลือกที่ deploy, Migration และการ deploy
container รันอยู่ตลอด server จึงรันงานตามเวลาเองทุกนาที และเก็บ SQLite กับไฟล์ อัปโหลดไว้บน volume ได้ การ build ใน image ยังทำให้ native driver ของ SQLite ตรงกับระบบที่รันจริงด้วย
1. Dockerfile
image จะ migrate ฐานข้อมูลตอน start แล้วจึงเสิร์ฟเว็บ เลือกตามแบบที่ใช้:
# Build: ติดตั้งทุกอย่างแล้ว build Next.js ไม่ต้องใช้ฐานข้อมูลตอน build
FROM node:24-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npx next build
# Run: แอปที่ build แล้วพร้อม node_modules (CLI easy-cms ใช้รัน migration)
FROM node:24-slim
WORKDIR /app
ENV NODE_ENV=production PORT=3000 HOSTNAME=0.0.0.0
COPY --from=build /app ./
EXPOSE 3000
HEALTHCHECK --interval=30s --start-period=30s \
CMD node -e "fetch('http://localhost:3000/api/cms/readyz').then(r => process.exit(r.ok ? 0 : 1), () => process.exit(1))"
CMD ["sh", "-c", "npx easy-cms migrate && npx next start"]FROM node:24-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npx nuxi build
FROM node:24-slim
WORKDIR /app
ENV NODE_ENV=production PORT=3000 HOST=0.0.0.0
COPY --from=build /app ./
EXPOSE 3000
HEALTHCHECK --interval=30s --start-period=30s \
CMD node -e "fetch('http://localhost:3000/api/cms/readyz').then(r => process.exit(r.ok ? 0 : 1), () => process.exit(1))"
CMD ["sh", "-c", "npx easy-cms migrate && node .output/server/index.mjs"]# image อย่างเป็นทางการ: easy-cms serve พร้อม adapter ที่ใช้บ่อย ดู "image อย่างเป็นทางการ" ข้างล่าง
FROM ghcr.io/maritonx/easy-cms:1
COPY easy-cms.config.ts ./
COPY easy-cms ./easy-cms- script
buildต้องไม่ migrate เพราะ image ถูก build โดยไม่มีฐานข้อมูล ให้รันnext build(หรือnuxi build) ตรงๆ แบบข้างบน - health check เรียก
/readyz: ฐานข้อมูลตอบและไม่มี migration ค้าง ดูHealth check - image แบบ standalone ต้องการแค่ config และ migration ของคุณ ตัว Easy CMS มาจากimage อย่างเป็นทางการ และฟังที่ port 4000
- ถ้าใช้ pnpm ให้เริ่ม stage build ด้วย
RUN corepack enableคัดลอกpnpm-lock.yamlและรันpnpm install --frozen-lockfile
กันไฟล์บนเครื่องไม่ให้เข้าไปใน image ด้วย .dockerignore:
node_modules
.next
.output
.env
.pglite
uploads
data
*.db
.gitimage อย่างเป็นทางการ
ghcr.io/maritonx/easy-cms รัน easy-cms serve ของเวอร์ชันตาม tag: 1.7.0, 1.7, 1 (1.x
ล่าสุด) และ latest สำหรับ linux/amd64 และ linux/arm64 ข้างในมี easy-cms, @easy-cms/core, adapter ของ
SQLite และ Postgres, S3 storage, อีเมล SMTP และ sharp สำหรับย่อรูป build จากแพ็กเกจบน npm
| ไฟล์ของคุณ | /app: คัดลอก easy-cms.config.ts และโฟลเดอร์ easy-cms (migration) ไปไว้ที่นี่ |
| ข้อมูล | /app/data เป็น volume: ชี้ SQLite (file:./data/cms.db) และไฟล์ upload บนดิสก์ (upload: { dir: './data/uploads' }) มาที่นี่ |
| Port | 4000 (PORT) |
| User | node ไม่ใช่ root |
| ตอนเริ่ม | easy-cms migrate แล้ว easy-cms serve --trust-proxy ตั้ง EASY_CMS_MIGRATE=false เพื่อข้าม migration |
| Health check | /readyz: ฐานข้อมูลตอบและไม่มี migration ค้าง |
แพ็กเกจอื่นที่ config import เช่น plugin ให้ติดตั้งด้วย npm install ใน Dockerfile ของคุณ:
FROM ghcr.io/maritonx/easy-cms:1
RUN npm install @easy-cms/plugin-seo@1 @easy-cms/plugin-redirects@1
COPY easy-cms.config.ts ./
COPY easy-cms ./easy-cmsใช้เวอร์ชันของแพ็กเกจเหล่านั้นให้ตรงกับ release ของ image ถ้ามีหลาย container บนฐานข้อมูลเดียวกัน ให้ migrate
ครั้งเดียวก่อนเริ่ม (ขั้น release หรือ init container ที่รัน easy-cms migrate) แล้วเริ่ม container ด้วย EASY_CMS_MIGRATE=false
2. Compose
services:
app:
build: .
ports:
- "3000:3000"
environment:
EASY_CMS_SECRET: ${EASY_CMS_SECRET:?set EASY_CMS_SECRET in .env}
EASY_CMS_SETUP_CODE: ${EASY_CMS_SETUP_CODE:-}
DATABASE_URL: postgres://cms:cms@db:5432/cms
volumes:
- uploads:/app/uploads
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:17
shm_size: 1g
environment:
POSTGRES_USER: cms
POSTGRES_PASSWORD: cms
POSTGRES_DB: cms
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U cms -d cms"]
interval: 5s
retries: 10
restart: unless-stopped
volumes:
uploads:
pgdata:services:
app:
build: .
ports:
- "3000:3000"
environment:
EASY_CMS_SECRET: ${EASY_CMS_SECRET:?set EASY_CMS_SECRET in .env}
EASY_CMS_SETUP_CODE: ${EASY_CMS_SETUP_CODE:-}
DATABASE_URL: file:/app/data/cms.db
volumes:
- data:/app/data
- uploads:/app/uploads
restart: unless-stopped
volumes:
data:
uploads:shm_size เผื่อพื้นที่ให้ Postgres ทำ parallel query: ค่าเริ่มต้นของ Docker คือ 64 MB ซึ่งไม่พอเมื่อตารางใหญ่ และ query
เหล่านั้นจะล้มด้วย "could not resize shared memory segment"
config อ่านฐานข้อมูลจาก DATABASE_URL เช่น postgres({ url: process.env.DATABASE_URL }) หรือ
sqlite({ url: process.env.DATABASE_URL }) ถ้าใช้ SQLite ให้รัน container เดียว เพราะไฟล์ SQLite มี server ได้ตัวเดียว
ถ้าใช้ image แบบ standalone ให้ map "4000:4000" และ mount volume data ที่ /app/data
ใส่ secret ในไฟล์ .env ข้าง compose.yaml (ไม่ใส่ใน image) แล้ว start:
printf 'EASY_CMS_SECRET=%s\nEASY_CMS_SETUP_CODE=%s\n' "$(openssl rand -hex 32)" "choose-a-phrase" > .env
docker compose up -d --build
docker compose logs -f applog จะแสดง migration ที่รัน แล้วตามด้วย server เปิด http://localhost:3000/admin แล้วสร้าง admin คนแรกด้วยรหัส
setup เปลี่ยนรหัสผ่าน Postgres ก่อนใช้ที่อื่นนอกจากเครื่องของคุณ
3. การอัปเดต
ดึงโค้ดใหม่แล้ว build ใหม่ container ใหม่จะรัน migration ที่ค้างก่อน start และ volume เก็บฐานข้อมูลกับไฟล์อัปโหลดไว้
git pull
docker compose up -d --build4. HTTPS และ proxy
วาง reverse proxy ไว้ข้างหน้าสำหรับ HTTPS เช่น Caddy, Traefik, nginx หรือของแพลตฟอร์ม proxy จะตั้ง
X-Forwarded-For ให้ จึงต้องเชื่อมัน: --trust-proxy (standalone ซึ่งอยู่ใน image ข้างบนแล้ว) หรือ
trustProxy: true (route handler ของ Next.js, module ของ Nuxt) จากนั้นตั้ง serverURL เป็นที่อยู่สาธารณะ
proxy ควร redirect HTTP ไป HTTPS ด้วย ตัวอย่างการตั้งค่า Caddy อยู่ใน VPS
สำรองข้อมูล
ทุกอย่างอยู่ใน volume: สำรอง volume pgdata หรือ data และ uploads หรือให้ Easy CMS สำรองฐานข้อมูลเอง
(backups ใน config เก็บไว้บน volume อื่นหรือใน S3) ดู สำรองข้อมูล
ขั้นต่อไป
- VPS: รันเว็บเดียวกันโดยไม่ใช้ container
- โฮสต์อื่นๆ: แพลตฟอร์มที่ build และรัน image นี้ให้