KDIGI CMS

KDIGI CMS

Tự host KDIGI CMS: Docker Compose, Coolify, VPS

Một máy Linux có Docker là đủ: một container ứng dụng và một PostgreSQL.

Cập nhật lần cuối:

Khối container và cơ sở dữ liệu kính mờ, đại diện cho việc tự host KDIGI CMS bằng Docker

Clone repo, chạy docker compose up -d --build là có server Next.js (admin và API, cổng 3000) cùng PostgreSQL. Có sẵn cấu hình cho Coolify và cách chạy không Docker.

Tóm tắt nhanh

  • Bốn cách: máy cá nhân, VPS Compose, Coolify, không Docker.
  • Biến tối thiểu: DATABASE_URI, PAYLOAD_SECRET, PAYLOAD_PUBLIC_SERVER_URL.
  • Migration tự chạy khi container khởi động.
  • Sao lưu cả database lẫn media.
  • Người đầu tiên tạo tài khoản thành super-admin.

Ảnh chụp bảng điều khiển KDIGI CMS sau khi cài đặt thành công

Bạn triển khai những gì

  • Ứng dụng Node 22 Alpine, next start, cổng 3000, chạy bằng user node.
  • PostgreSQL Service db đi kèm hoặc PostgreSQL managed qua DATABASE_URI.
  • Volume postgres_data, media_data (/app/media), app_data (/app/data).
  • Health GET /api/health chỉ là liveness, không truy vấn database.

Website công khai là frontend riêng gọi headless API; CMS không render trang thay bạn.

Cách 1: thử trên máy cá nhân

Chỉ cần Docker kèm Compose plugin:

git clone https://github.com/kdigivn/kdigi-cms-open.git
cd kdigi-cms-open
SEED_DEMO=true docker compose up --build

Mở http://localhost:3000/admin và tạo người dùng đầu tiên (tự động là super-admin). Bỏ SEED_DEMO=true để có bản cài trống. Chạy dev có hot reload: bắt đầu nhanh.

Cách 2: VPS với Docker Compose

  • Máy Linux có Docker và Compose plugin
  • RAM từ 2 GB
  • Domain đã trỏ về máy
git clone https://github.com/kdigivn/kdigi-cms-open.git
cd kdigi-cms-open
cat > .env <<'EOF'
POSTGRES_PASSWORD=change-me-to-a-long-random-password
PAYLOAD_SECRET=change-me-to-a-random-string-of-32-chars-or-more
PAYLOAD_PUBLIC_SERVER_URL=https://cms.example.com
ENABLE_JOBS_AUTORUN=true
EOF
docker compose up -d --build

Đặt reverse proxy kết thúc TLS phía trước và chặn cổng 3000 bằng tường lửa. Ví dụ Caddy:

cms.example.com {
    reverse_proxy 127.0.0.1:3000
}

Cảnh báo Không chạy SEED_DEMO=true trên bản production thật.

Cách 3: Coolify

  1. Tạo resource Chọn New Resource → Docker Compose, đặt Compose Location là /docker-compose.coolify.yml.
  2. Đặt biến bí mật Thêm PAYLOAD_SECRET (tạo bằng openssl rand -hex 32); đây là biến bắt buộc duy nhất.
  3. Gắn domain Vào service app (cổng 3000); domain riêng cần thêm PAYLOAD_PUBLIC_SERVER_URL.
  4. Deploy Lần đầu áp dụng mọi migration; mở /admin và tạo người dùng đầu tiên.

Các biến tùy chọn và cách sao lưu db trong Coolify: tài liệu Coolify.

Cách 4: không dùng Docker

Cần Node.js ≥ 20.9, pnpm 10 và PostgreSQL. Đặt DATABASE_URI, PAYLOAD_SECRET, PAYLOAD_PUBLIC_SERVER_URL, rồi chạy pnpm build, pnpm migrate, pnpm start dưới systemd hoặc pm2. Chi tiết: tài liệu triển khai.

Sau khi deploy

  1. Tạo người dùng đầu tiên ngay Trên database trống, ai mở /admin trước sẽ thành super-admin.
  2. Tạo site Nhập siteKey, domain, ngôn ngữ; xem quản lý nhiều website.
  3. Mời người dùng Gán vai trò và site (phân quyền).
  4. Bật job revalidate Đặt ENABLE_JOBS_AUTORUN=true trên đúng một instance.
  5. Chọn nơi lưu media Mặc định ổ đĩa; Cloudflare R2 theo từng site (thư viện media).

Sao lưu và khôi phục

Sao lưu cả database lẫn media, và giữ PAYLOAD_SECRET. Mất secret thì phiên đăng nhập và API key ngừng hoạt động, dữ liệu vẫn đọc được.

docker compose exec -T db pg_dump -U kdigi --format=custom kdigi > kdigi-$(date +%F).dump
docker compose exec -T app tar czf - -C /app/media . > media-$(date +%F).tgz
  • Chép dump ra khỏi máy chủ
  • Thử restore trên máy phụ
  • Site dùng R2: bật versioning phía Cloudflare
  • PostgreSQL managed: dùng snapshot của nhà cung cấp

Lệnh restore và quy trình đầy đủ: sao lưu và nâng cấp.

Nâng cấp

  1. Đọc CHANGELOG Tìm mục Breaking và biến môi trường mới (phát hành).
  2. Sao lưu Database và media.
  3. Lấy code mới, build lại docker compose up -d --build; Coolify thì redeploy.
  4. Kiểm tra Đăng nhập /admin, tải một ảnh, gọi một URL công khai.

Lưu ý Tránh pnpm migrate:down trên production: nó đảo ngược cả batch gần nhất. Khi cần quay lại, khôi phục bản sao lưu.

Bảo mật khi vận hành

  • PAYLOAD_SECRET ngẫu nhiên, từ 32 ký tự
  • Đặt CMS sau HTTPS
  • Giới hạn truy cập database trong mạng ứng dụng
  • Đổi POSTGRES_PASSWORD mặc định nếu cổng truy cập được từ ngoài
  • Giới hạn tốc độ request ở reverse proxy

Chi tiết: chính sách bảo mật và bảo mật, phân quyền.

Sự cố thường gặp

Triệu chứng Kiểm tra
Container khởi động lại, báo PAYLOAD_SECRET must be at least 32 characters Đặt secret ≥ 32 ký tự, hoặc bỏ đặt để entrypoint tự sinh
Đăng nhập admin lặp, API trả 403 PAYLOAD_PUBLIC_SERVER_URL phải khớp origin trên thanh địa chỉ
Không kết nối được database Trong Compose dùng host db, không dùng localhost
Ảnh tải lên mất sau redeploy /app/media chưa nằm trên volume bền
Frontend không làm mới sau khi đăng bài ENABLE_JOBS_AUTORUN=true trên một instance, đã đặt domain của site
Build bị kill, hết bộ nhớ Build trên máy lớn hơn hoặc thêm swap

Câu hỏi thường gặp

Cần cấu hình máy chủ tối thiểu để chạy KDIGI CMS?

Máy Linux có Docker kèm Compose plugin, RAM từ 2 GB và một domain trỏ về máy. Bước build tốn bộ nhớ: nếu bị out-of-memory, hãy build trên máy lớn hơn hoặc thêm swap.

KDIGI CMS chạy những thành phần nào?

Hai thành phần: server Next.js phục vụ cả trang quản trị lẫn API ở cổng 3000, và PostgreSQL. Ảnh tải lên nằm trên volume bền hoặc Cloudflare R2 theo từng site.

Biến môi trường nào là bắt buộc?

Ba biến: DATABASE_URI, PAYLOAD_SECRET (từ 32 ký tự khi chạy production) và PAYLOAD_PUBLIC_SERVER_URL (URL https công khai). Với docker compose up, entrypoint tự sinh PAYLOAD_SECRET.

Làm sao nâng cấp lên phiên bản mới?

Đọc CHANGELOG, sao lưu database và media, rồi git pull và docker compose up -d --build. Entrypoint tự chạy payload migrate trước khi khởi động; schema chỉ đổi qua migration.

Tôi cần sao lưu những gì?

Cả database PostgreSQL lẫn media, và giữ PAYLOAD_SECRET đang dùng. Site dùng Cloudflare R2 thì bật versioning ở phía Cloudflare. Hãy thử restore trên máy phụ trước khi cần đến.

Đọc tiếp