Quản lý nhiều website trong một hệ thống KDIGI CMS
Cập nhật lần cuối:

KDIGI CMS quản lý nhiều website bằng collection Sites: mỗi document là một website với siteKey và domain riêng, còn mọi nội dung đều thuộc đúng một site qua trường tenant. Một bản cài, một cơ sở dữ liệu phục vụ nhiều frontend; thêm site mới chỉ là nhập dữ liệu, không cần triển khai lại.
Tóm tắt nhanh
- Một document Sites = một website, định danh bằng
siteKey(duy nhất) vàdomain(tên miền thuần, không cóhttps://).- Nội dung cách ly theo site bằng trường
tenantvà các điều kiện truy cập tường minh trên từng thao tác.- Cấu hình riêng mỗi site: thương hiệu, trang chủ, liên hệ và footer, SEO, tích hợp GA4/GTM/Clarity, tùy chọn kho R2.
- Thêm site không cần deploy lại, không cần khởi động lại CMS.
- Frontend chọn site bằng
siteKey; CMS không suy luận site từ host của request.
Vì sao nên gộp nhiều website vào một CMS?
Khi agency hay doanh nghiệp có nhiều website, mỗi site một bản cài CMS kéo theo nhiều bản vá, nhiều bản sao lưu và nhiều tài khoản. KDIGI CMS gộp tất cả vào một hệ thống: một cơ sở dữ liệu PostgreSQL, một trang quản trị, một lần nâng cấp. Mỗi website vẫn có tên miền, thương hiệu, nội dung và nhóm biên tập riêng. Trên một install, người dùng chọn site đang làm việc bằng bộ chọn site và chỉ thấy dữ liệu của site đó.

Mô hình site trong KDIGI CMS
Collection sites (mã nguồn src/collections/sites.ts) là ranh giới tenant, cấu hình qua plugin @payloadcms/plugin-multi-tenant với tenantsSlug: 'sites'. Khi viết, tài liệu dùng từ "site"; trong mã nguồn bạn sẽ thấy tenant.
Các collection thuộc về một site gồm: pages, posts, products, landings, taxonomies, menus, faqs, authors, comments, shortcodes, redirects, cộng với media và thư mục media. Người dùng là dữ liệu dùng chung, được liên kết với site qua mảng users.tenants[].
Định danh site
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
siteKey |
text, bắt buộc, duy nhất | Mã ổn định (ví dụ my-blog). Frontend dùng để tìm site của mình |
domain |
text, bắt buộc | Tên miền chính, không có scheme và dấu / cuối (ví dụ www.example.com) |
defaultLanguage |
select, mặc định vi |
vi hoặc en; là ngôn ngữ của JSON-LD được sinh |
domain được ba nơi sử dụng: job revalidateFrontend (gọi POST https://<domain>/api/cms/revalidate sau khi nội dung đổi), bộ sinh JSON-LD (tạo URL canonical và các @id) và nút xem trên site (GET /api/frontend-doc-url).
Sáu tab cấu hình
Form Sites chia thành sáu tab, các trường nằm ở cấp cao nhất:
| Tab | Nội dung |
|---|---|
| Hệ thống | siteKey, domain, defaultLanguage, nhóm r2 |
| Thương hiệu | theme, branding (primaryColor, fontFamily, logo, favicon, notFoundImage) |
| Trang chủ | landing (hero, slider), featuredPosts, featuredProducts, homePageHighlight[] |
| Liên hệ & Footer | contact (nút liên hệ nổi, icon header), footer, sidebar |
| Trang & SEO | pageGroup[], seoDefaults, knowledgeGraph, socialProfiles[], seoTitles, breadcrumbs |
| Tích hợp | integration (ga4Id, gtmId, clarityId), manifest (PWA) |



Thương hiệu và giao diện theo từng site
theme: chọn một tronglight(mặc định),dark,brand-red,brand-blue,brand-green. Chỉ những theme mà frontend của bạn đã đăng ký mới hiển thị đúng. Thêm theme mới cần sửaTHEME_OPTIONSvà tạo migrationALTER TYPE "enum_sites_theme" ADD VALUE, vì danh sách là enum PostgreSQL.branding.primaryColor: màu CSS được kiểm tra hợp lệ (không chứa{ } < > " ' \;, tối đa 60 ký tự) vì frontend có thể chèn vào thẻ<style>`.branding.logo,favicon,notFoundImage: tải lên từ thư viện media của chính site.- Trang chủ:
landing.heroTitle, hai badgeheroNotice1/2,slider[]và các thẻ điểm nổi bậthomePageHighlight[](có bản địa hóa).
Cấu hình SEO riêng cho mỗi site
Mỗi site có mẫu tiêu đề seoTitles, ảnh Open Graph mặc định seoDefaults.ogImage, danh tính tổ chức knowledgeGraph và danh sách socialProfiles[] (xuất ra sameAs trong JSON-LD). Nhờ vậy mỗi website tự có đồ thị JSON-LD với Organization và WebSite của mình. Chi tiết xem SEO và JSON-LD.
Nhóm pageGroup[] ánh xạ các khóa chuẩn (FRONT_PAGE, BLOG, CONTACT, ABOUT, TERM_CONDITION, PRIVACY_POLICY…) sang slug thật của site, đọc qua GET /api/sites/:siteKey/env-page?key=<KEY>.
Kho lưu trữ media riêng cho từng site
Mặc định mọi upload lưu trên ổ đĩa, không cần tài khoản đám mây. Nếu muốn, site có thể dùng Cloudflare R2 riêng bằng cách điền nhóm r2: bucket, accountId, publicBaseUrl, hai khóa accessKeyId, secretAccessKey, cùng compressToWebp và webpQuality. Một site chỉ dùng R2 khi có cả bucket và accountId.
Nhóm r2 chỉ super-admin được ghi; hai khóa bí mật chỉ ghi (set qua POST /api/sites/:id/secret) và không bao giờ trả về qua REST hay GraphQL. Biến môi trường R2_OFF=true buộc mọi site dùng ổ đĩa cục bộ. Xem thêm thư viện media.
Cách ly dữ liệu: điều gì được bảo đảm
| Cơ chế | Vai trò |
|---|---|
| Bộ lọc danh sách và bộ chọn site của plugin | Chỉ để giao diện admin gọn gàng |
Các predicate tenantScopedRead, tenantScopedWrite, tenantScopedVersionsRead và quy tắc riêng cho media, payload-folders |
Ranh giới thật: ràng buộc where tường minh trên mọi thao tác |
| Quyền bọc của plugin (khóa phiên bản 3.90.2) | Lớp bổ sung cho người không phải super-admin |
| Đọc ẩn danh | Không tự lọc theo site: frontend phải thêm where[tenant][equals]=<id> |
Điểm cuối cùng rất quan trọng: nếu bạn quên bộ lọc tenant, request ẩn danh sẽ nhận nội dung đã xuất bản của tất cả site. Vì Sites cho phép đọc công khai, không bao giờ đặt bí mật vào trường Sites thông thường.
Frontend chọn site như thế nào
CMS không suy luận site từ host của request. Mỗi frontend được cấu hình siteKey của mình và tự giới hạn mọi truy vấn:
-
Tìm id site một lần rồi cache lại:
curl 'https://cms.example.com/api/sites?where[siteKey][equals]=my-blog&limit=1&depth=1' -
Lọc mọi truy vấn nội dung theo id đó:
curl 'https://cms.example.com/api/posts?where[tenant][equals]=1&where[status][equals]=published&locale=vi' -
Endpoint ghi công khai (
POST /api/comments/create,POST /api/ratings/submit) nhậntenantSiteKeythay vì id và từ chối document cha thuộc site khác. -
Truy cập server-to-server: tạo bản ghi Users, gán site trong
tenants[]và dùng khóa API (Authorization: users API-Key <key>); tài khoản này chỉ thấy bản nháp của site được gán.
Xem thêm Headless API để biết hợp đồng REST đầy đủ.
Thêm một website mới: 7 bước
- Đăng nhập super-admin. Ở bản cài mới, người dùng đầu tiên tạo trên màn hình "create first user" tự động là
super-admin. - Tạo site (Sites → Create): nhập
siteKey,domain,defaultLanguage. - Lưu trữ (tùy chọn): để trống
r2để dùng ổ đĩa, hoặc điền thông tin R2 của site. - Gán người dùng: mở Users, thêm dòng vào
tenantscho site. Người không phải super-admin không thấy gì cho đến khi có ít nhất một dòng. - Cấu hình site: thương hiệu, trang chủ, liên hệ và footer,
pageGroup,seoTitles,knowledgeGraph, tích hợp. - Tạo nội dung: menu, taxonomy, tác giả, trang và bài viết; mỗi mục được gắn site đang chọn.
- Trỏ frontend về URL của CMS với
siteKeymới và triển khaiPOST /api/cms/revalidatetrên domain của site để nội dung xuất bản làm mới bộ nhớ đệm.
Job revalidate chỉ chạy khi đặt ENABLE_JOBS_AUTORUN=true trên đúng một instance CMS.
Shortcode theo từng site
Shortcode là đoạn Markdown dùng lại (bảng giá, chính sách, boilerplate) và thuộc về một site. Hệ thống chỉ mở rộng shortcode của chính site chứa tài liệu: hai site có thể cùng định nghĩa pricing-note với nội dung khác nhau mà không xung đột. Cú pháp trong Markdown: [sc name="pricing-note" /]. Xem thêm tại trình soạn thảo Markdown.
Cái gì dùng chung, cái gì riêng theo site
| Hạng mục | Theo site? |
|---|---|
| Nội dung, taxonomy, menu, FAQ, shortcode, redirect, bình luận, tác giả | Có (tenant) |
| Tệp media và thư mục; kho lưu trữ | Có |
| Người dùng | Dùng chung; quyền truy cập qua tenants[] |
| Vai trò | Toàn cục (một người một vai trò trên mọi site của họ) |
Ngôn ngữ nội dung (vi, en) |
Toàn cục; defaultLanguage theo từng site |
| Biến môi trường (database, secret, jobs, khóa AI, reCAPTCHA) | Toàn cục trên cả cài đặt |
Khi nào dùng multi-site?
Mô hình này hợp với agency quản lý nhiều website khách hàng, với doanh nghiệp có nhiều thương hiệu hay nhiều tên miền, và với người đang gộp nhiều blog WordPress vào một hệ thống bằng pipeline chuyển từ WordPress. Nếu bạn chỉ có một website duy nhất, multi-site vẫn không tốn thêm: bạn chỉ dùng một site.
Bạn có thể thử ngay bằng demo trực tuyến, hoặc đọc hướng dẫn kỹ thuật về nhiều website trên trang tài liệu. Xem toàn bộ tính năng KDIGI CMS.
So với WordPress Multisite
WordPress Multisite là tính năng có sẵn của WordPress, cho phép tạo một "network" gồm nhiều website trên cùng một bản cài WordPress. Về nguyên tắc, hai bên cùng giải bài toán "một hệ thống, nhiều website", nhưng khác nhau ở kiến trúc:
| Điểm | WordPress Multisite | KDIGI CMS |
|---|---|---|
| Kiến trúc | Một bản cài WordPress phục vụ cả mạng site, có giao diện theme | CMS headless: chỉ quản trị và API, website là frontend riêng |
| Cách chọn site | Theo tên miền hoặc thư mục con của mạng site | Frontend tự gửi siteKey và lọc tenant; CMS không suy luận từ host |
| Cấu hình SEO theo site | Thường qua plugin SEO của bạn chọn | Có sẵn trong lõi: seoTitles, knowledgeGraph, JSON-LD theo từng site |
| Kho media | Do cấu hình của mạng site | Ổ đĩa mặc định, tùy chọn Cloudflare R2 riêng từng site |
Nếu bạn đang chạy WordPress Multisite và muốn chuyển sang, xem chuyển từ WordPress và so sánh KDIGI CMS với WordPress. Việc thiết lập hạ tầng cho nhiều site nằm ở trang tự host.
Nguồn
- WordPress, "Multisite" (tài liệu chính thức cho nhà phát triển WordPress): https://developer.wordpress.org/advanced-administration/multisite/ — truy cập ngày 2026-11-03.
- Mã nguồn và tài liệu KDIGI CMS: docs/multi-site.md.
Câu hỏi thường gặp
KDIGI CMS quản lý nhiều website như thế nào?
Thêm một website mới có cần triển khai lại CMS không?
Dữ liệu giữa các site có bị lẫn vào nhau không?
Mỗi site có thể dùng kho lưu trữ media riêng không?
Người dùng có thể thuộc nhiều site không?
Đọc tiếp
Phân quyền người dùng
Bốn vai trò super-admin, admin, editor, author; gán theo từng website; tác giả gửi bài chờ duyệt. Có tài khoản demo để thử ngay không cần cài đặt.
Headless API
Lấy nội dung qua REST hoặc GraphQL, Markdown chuyển sang HTML ở khóa gốc, hợp đồng revalidate cho ISR và ví dụ tích hợp Next.js chạy được ngay.
Thư viện media
Quản lý ảnh theo thư mục, sửa ảnh trực tiếp, nhập ảnh từ URL có chống SSRF, lưu trên ổ đĩa hoặc Cloudflare R2, xuất WebP để trang tải nhanh hơn.
Tự host
Cài KDIGI CMS trên VPS của bạn bằng Docker Compose hoặc Coolify: yêu cầu hệ thống, biến môi trường, sao lưu, nâng cấp và các bước tăng cường bảo mật.