Self-host Umami analytics: privacy-first cho landing dev solo

Mục lục
TL;DR
  • Umami là analytics open-source nhẹ, dùng Postgres (hoặc MySQL), không cần ClickHouse như Plausible. Setup nhanh nhất trong nhóm.
  • Cài bằng Docker compose mất 10 phút. Phù hợp VPS 2GB RAM, đủ chạy thêm Caddy + app khác.
  • Script tracking 2.5KB, không cookie, GDPR và Nghị định 13 compliant. Không cần cookie banner.
  • Tính năng: pageview, referrer, country, device, custom event, goal tracking, share dashboard public.
  • Free unlimited site và pageview, hoàn toàn không có giới hạn ngoài tài nguyên VPS.

Plausible mạnh nhưng cần ClickHouse, tốn thêm 2-3GB RAM. Google Analytics 4 phức tạp, lại lo cookie banner. Cho dev solo và freelancer host nhiều landing page cá nhân của client, cần một analytics nhẹ nhất có thể, chỉ 1 container Postgres và Umami là chạy được, không tốn tài nguyên VPS đang dùng cho mục đích khác. Umami là câu trả lời.

Bài này hướng dẫn tự host Umami từ A đến Z: dựng bằng Docker compose, dùng Postgres có sẵn hoặc tạo mới, đặt sau Caddy HTTPS, thêm 5 site cùng lúc, theo dõi custom event, chia sẻ dashboard công khai cho khách hàng. Test trên Cloud VPS 50 với Ubuntu 24.04. Sau bài này bạn có một analytics privacy-first cho mọi landing dev solo.

Umami so với Plausible và GA4

Tiêu chíUmamiPlausible CEGoogle Analytics 4
LicenseMITAGPLv3Proprietary
DatabasePostgres/MySQLClickHouse + PostgresBigQuery (cloud)
RAM idle200-400 MB1-2 GBN/A (cloud)
Setup time10 phút15 phút30+ phút config GA4
CookieKhôngKhôngCó (cần banner)
Script size2.5 KB1 KB45-60 KB
Funnel analysisCó (v2)Cloud only
UIModern, cleanModern, cleanPhức tạp
Cộng đồng VNLớn dầnLớnKhổng lồ

Umami nhẹ nhất, dễ setup nhất, phù hợp dev solo và freelancer host nhiều landing. Plausible mạnh hơn ở event volume và stability cho enterprise. GA4 mạnh nhất về tính năng nhưng nặng nề và lo về privacy.

Yêu cầu VPS

  • VPS tối thiểu 1 vCPU, 1 GB RAM, 20 GB SSD cho 1-3 site.
  • Khuyến nghị 2 vCPU, 2 GB RAM, 40 GB SSD cho 10-30 site nhỏ.
  • Postgres 13+ hoặc MySQL 8+.
  • Docker engine + Docker Compose.
  • Domain để đặt subdomain analytics.your-domain.com.

Cloud VPS 20 (1GB RAM) chạy được nếu Postgres dùng chung với app khác. Cloud VPS 50 (4GB RAM) thoải mái cho hàng chục site.

Bước 1: Tạo Postgres database

Nếu chưa có Postgres trên VPS:

sudo apt install -y postgresql-16
sudo systemctl enable postgresql
sudo -u postgres psql -c "CREATE DATABASE umami;"
sudo -u postgres psql -c "CREATE USER umami WITH PASSWORD '$YOUR_PASS';"
sudo -u postgres psql -c "GRANT ALL ON DATABASE umami TO umami;"
sudo -u postgres psql -d umami -c "GRANT ALL ON SCHEMA public TO umami;"

Hoặc dùng Postgres container trong docker compose (sẽ thấy ở bước 2).

Bước 2: Docker compose Umami

mkdir -p ~/umami && cd ~/umami

Tạo docker-compose.yaml (dùng Postgres riêng):

services:
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    container_name: umami
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://umami:$YOUR_PASS@umami-db:5432/umami
      DATABASE_TYPE: postgresql
      APP_SECRET: $YOUR_LONG_RANDOM_STRING_64CHAR
      TRACKER_SCRIPT_NAME: umami,script
    depends_on:
      umami-db:
        condition: service_healthy

  umami-db:
    image: postgres:16-alpine
    container_name: umami-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: $YOUR_PASS
    volumes:
      - ./umami-db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U umami"]
      interval: 10s

Khởi động:

docker compose pull
docker compose up -d
docker compose logs -f umami

Khi log thấy "ready - started server on 0.0.0.0:3000", Umami đã chạy. Truy cập http://server-ip:3000 thấy login screen.

Bước 3: Đăng nhập lần đầu

Mặc định Umami tạo admin: username "admin", password "umami". Login và đổi password ngay:

  1. Login admin/umami.
  2. Vào Settings > Profile > Change password. Đặt mật khẩu mạnh 16+ ký tự.
  3. Tạo user thêm trong Settings > Users nếu cần invite team.

Bước 4: Đặt Umami sau Caddy HTTPS

analytics.your-domain.com {
    reverse_proxy localhost:3000
    encode gzip
}

Reload Caddy, cert tự xin. Truy cập https://analytics.your-domain.com. Từ giờ chỉ vào qua HTTPS, không qua IP+port trần.

Bước 5: Thêm website đầu tiên

  1. Sidebar > Websites > Add website.
  2. Đặt Name (vd "Blog cá nhân") và Domain (vd "blog.your-domain.com").
  3. Save. Umami tạo Website ID dạng UUID.
  4. Click vào website > tab "Tracking code" copy snippet:

Paste vào thẻ của site. WordPress: plugin "Insert Headers and Footers". Next.js: trong _app.tsx hoặc layout.tsx. Static HTML: paste trực tiếp.

Mở site, refresh vài lần. Quay lại dashboard, sau 30-60 giây thấy pageview xuất hiện.

Bypass adblocker bằng custom script name

Một số adblocker chặn URL chứa "umami" hoặc "analytics". Workaround: đặt biến TRACKER_SCRIPT_NAME trong docker compose:

environment:
  TRACKER_SCRIPT_NAME: stats,assets/main

Restart Umami. Giờ tracker phục vụ tại /stats.js, /assets/main.js (cả hai đều work). Đổi src trong snippet tương ứng. Adblocker thông thường không chặn.

Custom event và goal

Ngoài pageview, Umami cho phép track custom event. Trong frontend:

// Khi user click signup
umami.track("Signup", { plan: "pro" });

// Hoặc thay tên event tự động cho hành động
umami.track((props) => ({ ...props, name: "Custom_View" }));

Hoặc data attribute không cần JS:

Mỗi click button gửi 1 event "Signup" kèm property plan. Dashboard có tab Events hiển thị breakdown.

Funnel và Goal (Umami v2)

Vào Reports > Create > Funnel. Đặt 3 step:

  1. Visit /landing.
  2. Click event "Signup".
  3. Visit /dashboard.

Umami tính tỉ lệ chuyển đổi giữa các step trong khoảng thời gian. Hữu ích cho landing page A/B test, signup flow analysis.

Chia sẻ dashboard công khai

Trong Website settings > General > "Share URL" toggle ON. Umami sinh URL dạng https://analytics.your-domain.com/share/randomkey/sitename.

Bất kỳ ai có link đều xem được dashboard (không cần login). Tiện cho:

  • Gửi client xem traffic landing của họ.
  • Public stat của blog cá nhân để xây dựng độ tin cậy.
  • Nhúng vào Notion hoặc Slite bằng iframe.

Phân quyền multi-team

Umami v2 hỗ trợ Teams. Tạo team:

  1. Settings > Teams > Create team.
  2. Invite user qua username (user phải tồn tại trong Umami).
  3. Assign role: Owner, Manager, Viewer.
  4. Move website vào team để team member access.

Phù hợp agency phục vụ nhiều client: mỗi client một team, share dashboard chỉ trong team đó.

Backup Postgres

0 3 * * * docker exec umami-db pg_dump -U umami umami 
  | gzip > /backup/umami-$(date +%F).sql.gz
find /backup -name "umami-*.sql.gz" -mtime +14 -delete

Cron 3 giờ sáng. Đẩy sang S3 bằng rclone nếu cần. Restore:

gunzip -c umami-2026-05-22.sql.gz | docker exec -i umami-db psql -U umami umami

Update Umami version mới

cd ~/umami
docker compose pull
docker compose down
docker compose up -d
docker compose logs -f umami

Umami v2 đã ổn định, ít breaking change. Vẫn nên backup Postgres trước update. Đọc release note để biết schema migration nếu có.

Performance khi nhiều site cùng track

Trên Cloud VPS 50 (4GB RAM, 2 vCPU), Umami xử lý ổn 50 site, tổng 500k-1M pageview/tháng. Khi vượt mức này, có thể tách Postgres ra VPS riêng để tăng I/O. Bottleneck đầu tiên là disk Postgres (insert event), CPU ít khi cao.

So sánh kích thước database

Pageview tích lũyUmami DB sizePlausible DB size
100k~50 MB~80 MB
1M~500 MB~700 MB
10M~5 GB~7 GB

Cả 2 đều tiết kiệm disk so với log raw. Khác biệt nhỏ. Quan trọng hơn là setup cron prune partition cũ sau 1-2 năm để DB không phình mãi.

FAQ

Umami có hỗ trợ subdomain wildcard không?

Không trực tiếp. Mỗi subdomain phải tạo website riêng. Workaround: dùng cùng script với data-domain wildcard "*.your-domain.com" và filter trong dashboard sau. Hoặc dùng 1 site duy nhất tên "all-subdomains" rồi track domain qua custom event property.

Umami có gửi alert khi traffic bất thường không?

Chưa có built-in. Workaround: dùng API /api/websites/:id/stats truy vấn theo cron, so sánh với baseline, gửi alert Telegram khi vượt ngưỡng (gấp 3x bình thường).

Umami chạy được trên MySQL không?

Có. Đổi image sang ghcr.io/umami-software/umami:mysql-latest và DATABASE_TYPE=mysql. Cấu trúc tương tự, performance ngang Postgres ở mức nhỏ. Postgres vẫn được khuyên dùng vì cộng đồng Umami test kỹ hơn.

Có thể import dữ liệu cũ từ GA4 vào Umami không?

Không trực tiếp. GA4 dữ liệu structure rất khác. Workaround: chạy GA4 và Umami song song 1-2 tuần, sau đó cancel GA4. Dữ liệu cũ GA4 export sang BigQuery để lưu trữ tham khảo.

Khi nào nên chọn Umami thay vì Plausible?

Chọn Umami khi: VPS RAM hạn chế (1-2GB), đã có Postgres sẵn không muốn thêm ClickHouse, ưu tiên setup nhanh nhất, host nhiều site nhỏ (>20). Chọn Plausible khi: cần tính năng nâng cao, có ngân sách RAM thoải mái, hoặc đã quen UI Plausible.

Cloud VPS cho vibe coder

Cloud VPS nhỏ vẫn chạy được Umami cho nhiều landing

Cloud VPS TND sẵn AlmaLinux 9, Ubuntu 22/24, Debian 12/13. SSD CEPH, snapshot 1-click, backup hằng ngày, network 200Mbps trong nước. Cloud VPS 20 (1GB RAM) đủ chạy Umami + Postgres cho 5-10 landing freelance.

Xem 8 cấu hình Cloud VPS →

Chia sẻ bài viết