# Cài Metabase trên VPS: Docker, PostgreSQL và user chỉ đọc

> Hướng dẫn cài Metabase trên VPS bằng Docker với PostgreSQL làm database ứng dụng, HTTPS, user database chỉ đọc, cấu hình RAM và sao lưu, hoặc cài bằng ZoPanel.

Source: https://zopanel.net/vi/blog/self-host-metabase  
Updated: 2026-10-21

## Ý chính

- Bản mã nguồn mở của Metabase miễn phí theo giấy phép AGPL; gói trả phí bắt đầu từ 100 $/tháng cho 5 người tại thời điểm viết.
- Metabase là ứng dụng Java: hãy tính 2 GB RAM và đặt heap bằng JAVA_OPTS, khoảng 1 GB trên server 2 GB.
- Khi chạy thật, lưu dữ liệu riêng của Metabase trong PostgreSQL; file H2 mặc định chỉ để dùng thử.
- Kết nối từng nguồn dữ liệu bằng một user database chỉ có quyền SELECT.

**Để cài Metabase, bạn chạy image Docker chính thức `metabase/metabase` với một database PostgreSQL lưu dữ liệu ứng dụng của nó, chỉ mở cổng 3000 trên `127.0.0.1` sau nginx có HTTPS, và đặt heap Java bằng `JAVA_OPTS` (khoảng `-Xmx1g` trên VPS 2 GB).** Sau đó kết nối từng database cần làm báo cáo bằng một **user chỉ đọc** riêng, không bao giờ dùng tài khoản của chính ứng dụng. Trên server có ZoPanel, Metabase cài một chạm từ Kho ứng dụng với SSL và khoá thiết lập, nhưng nó không đọc được database trên cùng server, nên thường được cài trên một server thứ hai.

Bài này gồm: giấy phép và chi phí của Metabase, cấu hình VPS, cài thủ công bằng Docker, tạo user chỉ đọc, cách cài bằng ZoPanel, sao lưu và cập nhật.

## Metabase là gì?

[Metabase](https://github.com/metabase/metabase) là công cụ business intelligence: bạn kết nối nó với MySQL, MariaDB, PostgreSQL và nhiều loại database khác, rồi tạo câu hỏi, biểu đồ và dashboard mà người không biết SQL vẫn lọc và chia sẻ được. Ví dụ chủ shop xem doanh thu theo ngày, theo kênh, mà không phải nhờ lập trình viên viết truy vấn. Metabase là ứng dụng Java.

**Giấy phép.** Theo [file giấy phép](https://github.com/metabase/metabase/blob/master/LICENSE.txt) của Metabase, mã nguồn nằm ngoài thư mục `enterprise` theo GNU AGPL, và image Docker `metabase/metabase` phát hành theo AGPL. Image `metabase/metabase-enterprise` theo giấy phép thương mại của Metabase.

**Phiên bản.** Tại thời điểm viết (tháng 10/2026), bản ổn định mới nhất là [v0.64.1](https://github.com/metabase/metabase/releases) ngày 7/10/2026. Metabase vẫn vá dòng trước đó: v0.63.20 ra ngày 19/10/2026.

## Metabase tự host so với các gói trả phí

Giá lấy từ [metabase.com/pricing](https://www.metabase.com/pricing/) tại thời điểm viết (tháng 10/2026):

| Gói | Giá | Số người kèm theo | Người thêm |
| --- | --- | --- | --- |
| Open Source (tự host) | Miễn phí | Không giới hạn | Không có |
| Starter | 100 $/tháng hoặc 1.080 $/năm | 5 | 6 $/người/tháng |
| Pro | 575 $/tháng hoặc 6.210 $/năm | 10 | 12 $/người/tháng |
| Enterprise | Từ 20.000 $/năm | Tuỳ thoả thuận | Tuỳ thoả thuận |

Bản mã nguồn mở có câu hỏi, dashboard và trình soạn SQL cho không giới hạn người dùng. Các gói trả phí thêm hỗ trợ và tính năng như phân quyền chi tiết hơn và các kiểu nhúng dashboard, triển khai trên cloud hoặc tự host tuỳ gói; hãy xem trang giá để biết cách chia hiện hành. Với nhóm nhỏ chỉ cần dashboard nội bộ, tự host bản mã nguồn mở tiết kiệm rõ ràng.

## Metabase cần bao nhiêu RAM?

[Hướng dẫn xử lý lỗi bộ nhớ](https://www.metabase.com/docs/latest/troubleshooting-guide/running) của Metabase cho biết JVM mặc định dùng khoảng một phần tư RAM của máy, để lại 1 đến 2 GB cho các tiến trình khác thường là đủ, và đưa ví dụ: `-Xmx1g` trên máy 2 GB, `-Xmx2g` trên máy 4 GB. [Hướng dẫn chạy production](https://www.metabase.com/learn/metabase-basics/administration/administration-and-operation/metabase-in-production) tính 40 người dùng đồng thời cần 3 nhân CPU và 5 GB RAM.

Thực tế: **2 GB RAM** cho một nhóm nhỏ, 4 GB nếu PostgreSQL và các dịch vụ khác chạy chung server hoặc nhiều người cùng mở dashboard. ZoPanel chạy Metabase với giới hạn 1536 MB.

## Cách 1: Cài Metabase thủ công bằng Docker

Dành cho VPS chưa có panel. Cài Docker Engine từ [kho của Docker](https://docs.docker.com/engine/install/ubuntu/) (các lệnh có trong bài [cài n8n trên VPS](/vi/blog/self-host-n8n)).

### Bước 1: File Compose với database ứng dụng PostgreSQL

[Tài liệu Docker](https://www.metabase.com/docs/latest/installation-and-operation/running-metabase-on-docker) của Metabase ghi rằng muốn chạy Metabase thật thì "cần lưu dữ liệu ứng dụng trong một database sẵn sàng cho production". File H2 nhúng mặc định chỉ hợp để dùng thử.

```bash
sudo mkdir -p /opt/metabase && cd /opt/metabase
sudo nano compose.yaml
```

```yaml
services:
  metabase-db:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_DB: metabaseappdb
      POSTGRES_USER: metabase
      POSTGRES_PASSWORD: doi-mat-khau-nay
    volumes:
      - ./pgdata:/var/lib/postgresql/data

  metabase:
    image: metabase/metabase:v0.64.1
    restart: unless-stopped
    depends_on:
      - metabase-db
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      MB_DB_TYPE: postgres
      MB_DB_DBNAME: metabaseappdb
      MB_DB_PORT: 5432
      MB_DB_USER: metabase
      MB_DB_PASS: doi-mat-khau-nay
      MB_DB_HOST: metabase-db
      JAVA_OPTS: "-Xmx1g"
      JAVA_TIMEZONE: Asia/Ho_Chi_Minh
```

```bash
sudo docker compose up -d
sudo docker compose logs -f metabase
```

Lần đầu khởi động mất một hai phút để Metabase tạo bảng.

### Bước 2: nginx và HTTPS

```nginx
server {
    listen 80;
    server_name bi.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 300s;
    }
}
```

Bật site và chạy `sudo certbot --nginx -d bi.example.com`. Mở tên miền ngay và hoàn tất **Let's get started**: tài khoản đầu tiên là quản trị viên. Sau đó, trong **Admin → Settings → General**, đặt **Site URL** là `https://bi.example.com`, và ở **Settings → Email** thêm SMTP để lời mời và email gửi dashboard định kỳ hoạt động.

## Tạo user database chỉ đọc cho Metabase

Metabase chỉ cần đọc. Nếu mật khẩu đã lưu bị lộ, hoặc ai đó viết một truy vấn SQL cẩu thả, user chỉ đọc sẽ giới hạn thiệt hại.

**MySQL hoặc MariaDB** (thay IP bằng địa chỉ server Metabase, hoặc `localhost` nếu cả hai chạy cùng máy):

```sql
CREATE USER 'metabase_ro'@'203.0.113.10' IDENTIFIED BY 'mot-mat-khau-dai-ngau-nhien';
GRANT SELECT ON shop.* TO 'metabase_ro'@'203.0.113.10';
```

**PostgreSQL:**

```sql
CREATE ROLE metabase_ro LOGIN PASSWORD 'mot-mat-khau-dai-ngau-nhien';
GRANT CONNECT ON DATABASE shop TO metabase_ro;
\c shop
GRANT USAGE ON SCHEMA public TO metabase_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO metabase_ro;
```

Dòng cuối áp dụng cho cả các bảng tạo sau này. Chỉ cho IP của server Metabase đi qua tường lửa, rồi thêm database ở **Admin → Databases → Add a database**.

**Nếu database nằm trên server ZoPanel**, tài liệu [Cơ sở dữ liệu](/vi/docs/databases) có hai công cụ. Thẻ **User database** (MariaDB) tạo thêm user với quyền bạn chọn, ví dụ chỉ `SELECT` để làm báo cáo; các user này kết nối từ chính server. **Truy cập từ xa** mở database cho các địa chỉ IP được liệt kê (tối đa 20 mục, không bao giờ "mọi nơi") và hiện **Chuỗi kết nối từ xa** cho user chính của database, user này có toàn quyền trên database đó. Để Metabase ở xa chỉ có quyền đọc, chủ server có thể mở **Truy cập từ xa** cho IP của server Metabase, rồi dùng quyền root của database tạo một user chỉ `SELECT` cho IP đó như lệnh ở trên.

## Cách 2: Cài Metabase bằng ZoPanel (một chạm)

Trên server có ZoPanel, Metabase nằm trong **Kho ứng dụng** ([hướng dẫn đầy đủ](/vi/docs/app-metabase)):

1. Mở **Kho ứng dụng**; nếu được hỏi, bấm **Cài Docker** trước.
2. Trên thẻ **Metabase**, bấm **Cài đặt**. Nhập **Tên miền** (ví dụ `bi.example.com`); quản trị viên chọn **Chủ sở hữu**. Giữ bật **SSL miễn phí (Let's Encrypt)**.
3. Theo dõi nhật ký tác vụ đến dòng `Metabase is available at http://<domain>`.

**Khoá thiết lập.** Người đầu tiên mở Metabase sẽ thành quản trị viên, nên khách truy cập chỉ thấy trang "đang được thiết lập" cho đến khi bạn xong:

1. Ở tab **Docker**, chờ trạng thái `running`, rồi bấm **Mở ứng dụng (chỉ mình tôi)** trong thẻ **Đang khoá thiết lập**. Lần đầu khởi động mất một đến hai phút.
2. Bấm **Let's get started**, nhập tên, email, công ty và mật khẩu, trả lời câu hỏi mục đích sử dụng, rồi thêm database hoặc chọn **I'll add my data later**.
3. Quay lại tab **Docker**, bấm **Đã thiết lập xong — mở công khai**.

**Cần biết trước khi chọn cách này:**

| Nguồn dữ liệu | Metabase trên ZoPanel kết nối được? |
| --- | --- |
| Database trên server khác, qua địa chỉ công khai | Có |
| Database cloud được quản lý có endpoint công khai | Có |
| MariaDB hay PostgreSQL trên cùng server | Không, dù bạn nhập host nào |
| Mạng nội bộ và endpoint chỉ có trong VPC | Không |

Container bị chặn khỏi cổng database của server có chủ đích, để một ứng dụng bị lợi dụng không chạm được dữ liệu của khách khác. Cách thường dùng là cài Metabase trên server ZoPanel thứ hai và kết nối tới server thứ nhất qua **Truy cập từ xa**. Metabase của ZoPanel lưu dữ liệu riêng trong file H2 (`MB_DB_FILE`), dùng dòng phát hành 0.63 và chạy với giới hạn 1536 MB RAM. Vì H2 kém bền hơn PostgreSQL, hãy đặt **Lịch** sao lưu.

## Sao lưu Metabase

Dữ liệu báo cáo vẫn nằm trong database nguồn. Thứ cần sao lưu là **database ứng dụng** của Metabase: người dùng, câu hỏi, dashboard, collection và các kết nối đã lưu.

- **Database ứng dụng PostgreSQL:** `sudo docker compose exec -T metabase-db pg_dump -U metabase metabaseappdb > /root/metabase-$(date +%F).sql`
- **File H2:** [hướng dẫn sao lưu](https://www.metabase.com/docs/latest/installation-and-operation/backing-up-metabase-application-data) của Metabase yêu cầu dừng Metabase, chép file `metabase.db.mv.db`, rồi khởi động lại.
- **ZoPanel:** dữ liệu ứng dụng không nằm trong bản sao lưu tài khoản. Dùng **Sao lưu ngay** ở thẻ **Sao lưu** trong tab **Docker**, và quản trị viên đặt **Lịch** hằng ngày hoặc hằng tuần. Container tạm dừng vài giây để file H2 nhất quán.

Hãy chép bản sao lưu ra ngoài server và mã hoá: chúng chứa mật khẩu của mọi kết nối database đã lưu. Xem bài [chiến lược sao lưu website](/vi/blog/website-backup-strategy).

## Cập nhật Metabase

1. Sao lưu database ứng dụng. Metabase chuyển đổi nó khi khởi động và không hỗ trợ hạ phiên bản.
2. Đổi tag image, rồi chạy `sudo docker compose pull && sudo docker compose up -d`.
3. Metabase sẽ gián đoạn một đến hai phút trong lúc khởi động.

Trên ZoPanel, **Cập nhật bản mới** mang về bản vá 0.63 mới nhất; các dòng mới hơn đến cùng bản cập nhật ZoPanel.

## Kết luận

Tự host Metabase chủ yếu xoay quanh ba thiết lập: một database ứng dụng thật, heap Java hợp lý và quyền chỉ đọc vào dữ liệu. Làm đúng ba điều đó, bản mã nguồn mở cho nhóm nhỏ những dashboard tương đương gói trả phí mà không tốn phí theo đầu người. Nếu bạn muốn Metabase và các ứng dụng khác chạy trên server đã có sẵn SSL, cách ly và sao lưu ứng dụng, hãy bắt đầu với gói Free của ZoPanel và xem [tính năng database](/vi/features/databases):

```bash
curl -fsSL https://get.zopanel.net | sudo bash
```

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

### Tự host Metabase có miễn phí không?

Có. Bản mã nguồn mở miễn phí theo AGPL, không giới hạn người dùng. Gói trả phí thêm hosting, hỗ trợ và tính năng, bắt đầu từ 100 $/tháng cho 5 người tại thời điểm viết.

### Metabase cần bao nhiêu RAM?

Hãy tính tối thiểu 2 GB và đặt `-Xmx1g`, theo hướng dẫn của Metabase là để lại 1 đến 2 GB cho các tiến trình khác. Metabase tính 40 người dùng đồng thời cần khoảng 3 nhân CPU và 5 GB RAM.

### Database H2 mặc định có dùng thật được không?

Metabase khuyên dùng database ứng dụng sẵn sàng cho production như PostgreSQL hoặc MySQL. H2 ổn khi dùng thử hoặc với bản cài rất nhỏ có sao lưu đều đặn; hãy chuyển đổi trước khi phụ thuộc vào nó.

### Metabase có sửa được dữ liệu trong database của tôi không?

Metabase được làm để đọc, nhưng truy vấn SQL gốc chạy với đúng quyền của user kết nối. Hãy dùng user chỉ có `SELECT`, và kiểm soát ai được viết SQL ở **Admin → Permissions**.

### Metabase có sao chép dữ liệu của tôi không?

Không. Nó lưu câu hỏi, dashboard và cấu hình kết nối trong database ứng dụng, và truy vấn database nguồn mỗi khi câu hỏi chạy. Ngoại lệ là kết quả được cache, nếu bạn bật tính năng cache.
