---
createdAt: 2026-06-30
updatedAt: 2026-06-30
title: Tự host Intlayer
description: Chạy một phiên bản Intlayer hoàn chỉnh trên hạ tầng của riêng bạn chỉ với một lệnh duy nhất. Không yêu cầu tài khoản Intlayer Cloud.
keywords:
- Self-Hosting
- Docker
- Docker Compose
- Intlayer
- CMS
- Installation
- Infrastructure
slugs:
- doc
- self-hosting
author: aymericzip
---
# Tự host Intlayer
Intlayer có thể chạy hoàn toàn trên hạ tầng của riêng bạn — không yêu cầu tài khoản Intlayer Cloud. Chỉ một lệnh duy nhất sẽ khởi động một stack sẵn sàng cho production:
```sh
curl -fsSL https://intlayer.org/install.sh | sh
```
Trình cài đặt sẽ tải xuống `docker-compose.yml` và `.env`, tự động tạo các secret cần thiết, và khởi động tất cả các container với `docker compose up -d`.
## Mục lục
---
## Kiến trúc
```
┌─────────────────────────────┐
browser ──────▶ │ app (TanStack Start) :3000│ ──┐
└─────────────────────────────┘ │ VITE_BACKEND_URL
┌─────────────────────────────┐ │
│ backend (Fastify/Bun) :3100│ ◀─┘
└──────────────┬──────────────┘
┌──────────┬─────────┼──────────┬───────────┐
▼ ▼ ▼ ▼ ▼
mongo:27017 redis:6379 minio:9000 mailpit:1025 Chromium
(1-node RS) (S3 API) (SMTP) (in-image)
minio:9001 mailpit:8025
(console) (web UI)
```
Chromium (được sử dụng để tạo ảnh chụp màn hình Puppeteer) được đóng gói bên trong image backend — không cần container riêng.
---
## Điều kiện tiên quyết
- **Docker** ≥ 24 và **Docker Compose** ≥ v2. Nếu thiếu một trong hai, trình cài đặt sẽ in liên kết cài đặt và thoát.
- Các cổng `3000`, `3100`, `8025`, `9000`, và `9001` phải khả dụng trên host.
- Host chạy Linux hoặc macOS (hoặc WSL2 trên Windows).
---
## Bắt đầu nhanh
```sh
curl -fsSL https://intlayer.org/install.sh | sh
```
Những gì trình cài đặt thực hiện:
1. Kiểm tra xem `docker` và `docker compose` có tồn tại không.
2. Tải xuống `docker-compose.yml` và `.env.example` vào `./intlayer/`.
3. Nếu không có `.env` tồn tại, sao chép file ví dụ và tạo các secret ngẫu nhiên cho `BETTER_AUTH_SECRET`, `S3_ACCESS_KEY_ID`, và `S3_SECRET_ACCESS_KEY` thông qua `openssl rand`.
4. Chạy `docker compose pull` + `docker compose up -d`.
5. In các URL: dashboard `:3000`, API `:3100`, UI email `:8025`, console MinIO `:9001`.
Sau khi stack hoạt động, mở **http://localhost:3000** và tạo tài khoản đầu tiên của bạn.
---
## Các dịch vụ
| Dịch vụ | Image | Cổng Host | Mục đích |
| ----------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------- |
| **app** | được xây dựng từ `apps/app/Dockerfile` | `3000` | Dashboard TanStack Start (UI của CMS) |
| **backend** | được xây dựng từ `apps/backend/Dockerfile` | `3100` | API REST Fastify (endpoint `/health`) |
| **mongo** | `mongo:7` | nội bộ | Bộ nhân bản một node (`rs0`) |
| **redis** | `redis:7-alpine` | nội bộ | Hàng đợi công việc (BullMQ) và caching (ioredis) |
| **minio** | `minio/minio` | `9000` (S3), `9001` (console) | Lưu trữ đối tượng tương thích S3 cho avatar và ảnh chụp màn hình |
| **mailpit** | `axllent/mailpit` | `1025` (SMTP), `8025` (web UI) | Nơi nhận email giao dịch cục bộ |
Các cổng nội bộ (mongo, redis) không được phơi bày ra host theo mặc định.
> Cổng MinIO `9000` phải có thể truy cập được bởi trình duyệt vì các tài sản được tải lên (avatars, ảnh chụp màn hình) được tải trực tiếp từ `S3_PUBLIC_URL=http://localhost:9000/intlayer`.
---
## Các biến môi trường
Trình cài đặt tạo ra một file `.env` sẵn sàng để sử dụng. Bảng dưới đây mô tả từng biến.
### Bắt buộc (tự động tạo hoặc được nhắc nhở)
| Biến | Ví dụ | Mô tả |
| ---------------------- | ----------------------------------------------- | ------------------------------------------------- |
| `NODE_ENV` | `production` | Môi trường runtime |
| `PORT` | `3100` | Cổng lắng nghe của Backend |
| `BACKEND_URL` | `http://localhost:3100` | URL công khai của API backend |
| `APP_URL` | `http://localhost:3000` | URL công khai của dashboard |
| `DOMAIN` | `localhost` | Miền cookie |
| `MONGODB_URI` | `mongodb://mongo:27017/intlayer?replicaSet=rs0` | URI kết nối MongoDB đầy đủ |
| `REDIS_URL` | `redis://redis:6379` | URL kết nối Redis |
| `BETTER_AUTH_SECRET` | _(được tạo)_ | Secret 32-byte để ký session |
| `MAIL_PROVIDER` | `smtp` | Phương thức gửi mail: `smtp` hoặc `resend` |
| `MAIL_SMTP_HOST` | `mailpit` | Tên host SMTP (tên container Mailpit) |
| `MAIL_SMTP_PORT` | `1025` | Cổng SMTP |
| `MAIL_FROM` | `Intlayer ` | Địa chỉ người gửi |
| `S3_ENDPOINT` | `http://minio:9000` | Endpoint tương thích S3 |
| `S3_PUBLIC_URL` | `http://localhost:9000/intlayer` | URL công khai để trình duyệt tải tài sản |
| `S3_BUCKET_NAME` | `intlayer` | Tên bucket |
| `S3_ACCESS_KEY_ID` | _(được tạo)_ | Khóa truy cập MinIO |
| `S3_SECRET_ACCESS_KEY` | _(được tạo)_ | Khóa bí mật MinIO |
| `VITE_BACKEND_URL` | `http://localhost:3100` | URL backend được tích hợp vào dashboard khi build |
| `VITE_DOMAIN` | `localhost` | Miền được tích hợp vào dashboard khi build |
### Tùy chọn (tính năng sẽ suy giảm khi không có)
| Biến | Tính năng |
| -------------------------------------------------------- | -------------------------------------------------------------- |
| `OPENAI_API_KEY` | Dịch thuật và kiểm tra nội dung có sự hỗ trợ của AI |
| `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `STRIPE_*` | Quản lý thanh toán và đăng ký |
| `RESEND_API_KEY` | Email giao dịch qua Resend (ghi đè Mailpit khi được thiết lập) |
| `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET` | Đăng nhập GitHub OAuth |
| `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` | Đăng nhập Google OAuth |
| `GITLAB_CLIENT_ID`, `GITLAB_CLIENT_SECRET` | Đăng nhập GitLab OAuth |
| `MICROSOFT_CLIENT_ID`, `MICROSOFT_CLIENT_SECRET` | Đăng nhập Microsoft OAuth |
| `LINKEDIN_CLIENT_ID`, `LINKEDIN_CLIENT_SECRET` | Đăng nhập LinkedIn OAuth |
| `ATLASSIAN_CLIENT_ID`, `ATLASSIAN_CLIENT_SECRET` | Đăng nhập Atlassian OAuth |
---
## Kết nối dự án Intlayer của bạn
Khi stack đang chạy, hãy trỏ dự án của bạn đến backend và dashboard được tự host thay vì `intlayer.org`.
### Cấu hình dự án
```typescript fileName="intlayer.config.ts" codeFormat={["typescript", "esm", "commonjs"]}
import type { IntlayerConfig } from "intlayer";
const config: IntlayerConfig = {
editor: {
clientId: process.env.INTLAYER_CLIENT_ID,
clientSecret: process.env.INTLAYER_CLIENT_SECRET,
/**
* URL của dashboard CMS được tự host.
* Mặc định: https://app.intlayer.org
*/
cmsURL: process.env.INTLAYER_CMS_URL, // ví dụ: http://localhost:3000
/**
* URL của API backend được tự host.
* Mặc định: https://back.intlayer.org
*/
backendURL: process.env.INTLAYER_BACKEND_URL, // ví dụ: http://localhost:3100
},
};
export default config;
```
Thiết lập các biến môi trường trong file `.env` của dự án bạn:
```sh
INTLAYER_CMS_URL=http://localhost:3000
INTLAYER_BACKEND_URL=http://localhost:3100
INTLAYER_CLIENT_ID=
INTLAYER_CLIENT_SECRET=
```
Tạo thông tin truy cập trong dashboard được tự host của bạn dưới mục **Projects → Access keys** tại `http://localhost:3000/projects`.
### SDK `@intlayer/api`
Khi sử dụng SDK `@intlayer/api` theo cách lập trình, hãy truyền `backendURL` một cách rõ ràng:
```typescript fileName="cms.ts" codeFormat="typescript"
import { createIntlayerCMS } from "@intlayer/api";
import { dictionaryEndpoint } from "@intlayer/api/dictionary";
const cms = createIntlayerCMS({
editor: {
clientId: process.env.INTLAYER_CLIENT_ID,
clientSecret: process.env.INTLAYER_CLIENT_SECRET,
backendURL: process.env.INTLAYER_BACKEND_URL, // http://localhost:3100
},
});
const { data: dictionaries } = await dictionaryEndpoint(cms).getDictionaries();
```
---
## Nâng cấp
Chạy lại trình cài đặt trên một triển khai hiện có sẽ thực hiện nâng cấp cuốn chiếu (rolling upgrade):
```sh
curl -fsSL https://intlayer.org/install.sh | sh
```
Thao tác này sẽ kéo các image mới nhất và khởi động lại các container với `docker compose pull && docker compose up -d`. Các volume hiện có (`mongo-data`, `redis-data`, `minio-data`) được bảo toàn — không mất dữ liệu.
Để nâng cấp thủ công từ bên trong thư mục `./intlayer/`:
```sh
docker compose pull
docker compose up -d
```
---
## Sao lưu và phục hồi
Tất cả dữ liệu bền vững nằm trong ba Docker volume được đặt tên.
### Sao lưu
```sh
docker run --rm \
-v intlayer_mongo-data:/data \
-v "$(pwd)":/backup \
busybox tar czf /backup/mongo-data.tar.gz /data
docker run --rm \
-v intlayer_redis-data:/data \
-v "$(pwd)":/backup \
busybox tar czf /backup/redis-data.tar.gz /data
docker run --rm \
-v intlayer_minio-data:/data \
-v "$(pwd)":/backup \
busybox tar czf /backup/minio-data.tar.gz /data
```
### Phục hồi
```sh
docker run --rm \
-v intlayer_mongo-data:/data \
-v "$(pwd)":/backup \
busybox tar xzf /backup/mongo-data.tar.gz -C /
# Lặp lại cho redis-data và minio-data
```
---
## Sử dụng reverse proxy (Nginx / Caddy)
Đối với các triển khai production, hãy đặt một reverse proxy phía trước các container app và backend thay vì phơi bày chúng trực tiếp.
### Ví dụ Nginx
```nginx
server {
listen 80;
server_name cms.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://localhost:3100;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
Cập nhật các biến `.env` sau để khớp với các miền công khai của bạn:
```sh
BACKEND_URL=https://api.example.com
APP_URL=https://cms.example.com
DOMAIN=example.com
VITE_BACKEND_URL=https://api.example.com
VITE_DOMAIN=example.com
```
> Các biến `VITE_*` được tích hợp vào image dashboard tại thời điểm build. Nếu bạn thay đổi chúng sau khi image được build, bạn cần build lại image `app` (`docker compose build app`) hoặc sử dụng cấu hình runtime injection.
---
## Khắc phục sự cố
### Backend bị crash-loop khi khởi động lần đầu
MongoDB và Redis phải hoạt động tốt trước khi backend khởi động. File compose sử dụng `depends_on` với `condition: service_healthy`. Nếu bạn thấy backend khởi động lại liên tục, hãy kiểm tra xem healthcheck của `mongo` và `redis` có vượt qua không:
```sh
docker compose ps
docker compose logs mongo
docker compose logs redis
```
### Dashboard không thể kết nối tới API
Xác minh rằng `VITE_BACKEND_URL` khớp với URL mà backend có thể truy cập được từ **trình duyệt** (không phải mạng Docker). Nếu bạn đã thay đổi cổng backend hoặc thêm reverse proxy, hãy build lại image dashboard:
```sh
docker compose build app
docker compose up -d app
```
### Email không gửi được
Theo mặc định, tất cả email gửi đi được Mailpit thu nhận. Mở `http://localhost:8025` để xem các tin nhắn đã gửi. Để gửi email thật, hãy đặt `MAIL_PROVIDER=resend` và `RESEND_API_KEY=` trong `.env`, sau đó khởi động lại backend:
```sh
docker compose restart backend
```
### Thiếu MinIO bucket
Nếu dịch vụ một lần chạy `minio-init` không chạy (hoặc chạy trước khi MinIO sẵn sàng), hãy tạo bucket thủ công:
```sh
docker compose run --rm minio-init
```
---
## Các liên kết hữu ích
- [Tài liệu Intlayer CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/intlayer_CMS.md)
- [Tham chiếu cấu hình](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/configuration.md)
- [CMS SDK — `@intlayer/api`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/intlayer_CMS.md#programmatic-access-with-the-intlayerapi-sdk)