SSD Nodes Learn 🎉 VPS từ $4.99/tháng
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-07

Tự host Superlog: Cài đặt và footprint thực tế

Tìm hiểu Superlog cài gì khi tự host: Postgres, ClickHouse, OpenTelemetry collector và 4 Node service, cùng lưu ý repo chưa có release tag.

Superlog thực sự cài những gì khi tự host

Để tự host Superlog, bạn clone repository, khởi động Postgres, ClickHouse và một OpenTelemetry collector bằng Docker Compose, chạy một lần database migration, rồi khởi động 4 Node service từ source. Ứng dụng của bạn gửi trace, log và metric OTLP (giao thức OpenTelemetry) đến một intake port. Superlog fingerprint chúng, nhóm các sự kiện lặp lại thành một incident duy nhất, rồi một agent tạo bản triage ban đầu. Quá trình cài đặt mất một buổi chiều. Trước khi bắt đầu, bạn nên đọc kỹ phần footprint và các giới hạn thực tế.

Superlog được cấp phép theo Apache 2.0 và nằm tại github.com/superloglabs/superlog. Tính đến tháng 8 năm 2026, repository này có khoảng 1.2k star, khoảng 460 commit trên main và hoàn toàn không có release tag. Điểm cuối cùng này ảnh hưởng trực tiếp đến cách cài đặt: git checkout v1.0.0 không có gì để checkout, nên bạn phải tự pin một commit hoặc chạy đúng phiên bản main có trong repository vào buổi sáng bạn clone nó.

Superlog giải đáp điều gì mà Uptime Kuma và Langfuse không giải đáp được

Nhìn từ bên ngoài, các công cụ monitoring tự host có vẻ có thể thay thế cho nhau. Thực tế không phải vậy, và chọn sai công cụ sẽ tốn tài nguyên server mà không đem lại lợi ích.

Superlog tập trung vào một câu hỏi khác: có gì hỏng, thành phần nào hỏng và vì sao. Nó không xử lý các cuộc gọi LLM và cũng không kiểm tra hệ thống của bạn từ bên ngoài. Nó nhận dữ liệu OTLP từ code ứng dụng thông thường và đặt một agent vào bước triage, tức lượt kiểm tra đầu tiên mà người trực on-call cũng sẽ thực hiện.

Điểm khác biệt quan trọng đối với ngân sách VPS là storage. Uptime Kuma chạy ổn với 1 GB RAM vì chỉ lưu vài nghìn kết quả kiểm tra. Superlog dùng column store vì telemetry được ghi một lần rồi truy vấn theo khoảng thời gian trên hàng triệu dòng. Đó là lý do dùng ClickHouse, còn Postgres thì không phù hợp cho việc này. Postgres vẫn nằm trong stack để lưu dữ liệu quan hệ nhỏ: project, user, incident và ingest key.

docker compose up -d thực sự khởi động những gì?

Ba container, và không container nào là Superlog. Điều này khiến những người kỳ vọng cài đặt chỉ bằng một lệnh bất ngờ.

  • postgres:16, được publish trên cổng 5434 của host
  • clickhouse/clickhouse-server:26.1, dùng cổng 8123 cho HTTP và 9000 cho native protocol
  • otel/opentelemetry-collector-contrib:0.150.1, dùng cổng 4317 cho gRPC và 4318 cho OTLP over HTTP

Các ứng dụng Superlog chạy trực tiếp trên host từ source, được khởi động bằng pnpm dev. Tính đến tháng 8 năm 2026, repository không có compose file dành cho production. Vì vậy, để chạy lâu dài, bạn phải tự tạo các systemd unit cho từng ứng dụng quanh script start tương ứng, hoặc dùng các Dockerfile riêng của từng ứng dụng có sẵn trong cây thư mục.

Hãy ghi nhớ đường đi của một span, vì mỗi lỗi bên dưới đều là một điểm đứt trên một chặng của đường đi đó. Ứng dụng của bạn gửi OTLP đến Superlog intake proxy. Proxy xác thực request bằng ingest key của bạn, gắn project id vào request, rồi chuyển tiếp request đến collector. Collector loại bỏ mọi thuộc tính superlog.* mà client cố gắng tự đặt, thêm superlog.project_id từ header do proxy cung cấp, gom batch rồi ghi dữ liệu vào ClickHouse. Web app và API đọc telemetry từ ClickHouse, còn mọi dữ liệu khác được đọc từ Postgres.

Việc loại bỏ thuộc tính này là một cơ chế kiểm soát multi-tenancy thực sự, không phải phần trang trí. Nếu không có cơ chế đó, bất kỳ ai có một ingest key hợp lệ cũng có thể tự đặt superlog.project_id và ghi dữ liệu vào project khác.

VPS cần cấu hình lớn đến mức nào?

Với một node duy nhất và lưu lượng ingest thấp, hãy dự trù 4 vCPU, 8 GB RAM và 40 GB SSD. Đây là mức sàn để lập kế hoạch, không phải số đo thực tế. Hãy xem đó là cấu hình khởi điểm và đối chiếu với lưu lượng của bạn.

RAM được dùng cho 4 thành phần. ClickHouse được thiết kế cho các máy có nhiều RAM và các giá trị mặc định của nó cũng giả định như vậy. Postgres 16 chỉ chiếm mức vừa phải trong trường hợp này vì nó lưu metadata thay vì telemetry. Collector cũng không đáng kể. Bốn tiến trình Node thì khác: một server phát triển Vite cộng với 3 tiến trình tsx watch mỗi tiến trình có thể chiếm hàng trăm megabyte. Vì vậy, chạy pnpm dev trên máy 2 GB sẽ rất khó chịu.

Disk là vấn đề ít rõ ràng hơn. pnpm install trong monorepo này kéo về AWS SDK, client ClickHouse, OpenTelemetry SDK và toolchain React trước khi bạn ingest một span nào. Sau đó ClickHouse tiếp tục tăng theo lưu lượng. Hãy đo cả 2 phần:

df -h /
free -m
docker stats --no-stream
docker compose exec clickhouse clickhouse-client --database superlog --query "SELECT table, formatReadableSize(sum(bytes_on_disk)) AS size FROM system.parts WHERE active AND database = 'superlog' GROUP BY table ORDER BY sum(bytes_on_disk) DESC"

Ở lưu lượng thấp, với một số ít service gửi vài trăm span mỗi phút, máy hoạt động nhẹ và ClickHouse hầu như ở trạng thái idle. Burst mới là loại tải gây vấn đề: một lần deploy lỗi có thể tạo ra hàng nghìn lỗi giống hệt nhau mỗi phút. Fingerprinting gộp chúng thành một incident đối với người đọc, nhưng ClickHouse vẫn ghi từng row ở bên dưới.

Bạn tự đặt thời gian retention. ClickHouse exporter của collector tạo các table, otel_traces, otel_logs và một table cho từng loại metric. Exporter chỉ áp dụng time to live nếu cấu hình trong infra/collector/config.yaml đặt giá trị này. Không có dữ liệu nào tự hết hạn, nên một tháng có lưu lượng cao sẽ làm đầy disk nếu bạn không lập kế hoạch trước.

Cài đặt từ một commit cố định

git clone https://github.com/superloglabs/superlog.git
cd superlog
git tag -l
git log -1 --format='%H %cs %s'

git tag -l không in gì là kết quả đúng tính đến August 2026. Chọn commit bạn đã kiểm thử và giữ nguyên commit đó:

git checkout 0d3a6c8bb63eda3493e6ba0003e7c2a70750bc1e

Tiếp theo là toolchain:

node -v
corepack enable
corepack prepare pnpm@9.12.0 --activate
pnpm -v

package.json khai báo engines.node>=20.0.0packageManagerpnpm@9.12.0. Chạy quá trình cài đặt trên Node cũ hơn thì pnpm dừng với ERR_PNPM_UNSUPPORTED_ENGINE và ghi rõ phiên bản cần dùng. Gói nodejs trong kho Ubuntu 24.04 cũ hơn 20, vì vậy hãy cài Node 20 hoặc mới hơn từ NodeSource hoặc nvm. Repository có một .nvmrc, nên nvm use sẽ chọn đúng phiên bản nếu bạn dùng nvm.

pnpm install
docker compose up -d
docker compose ps

Hãy chờ các health check thay vì mặc định up -d có nghĩa là service đã sẵn sàng. Postgres và ClickHouse đều khai báo health check trong compose file:

curl -sS http://127.0.0.1:8123/ping
pg_isready -h 127.0.0.1 -p 5434 -U postgres

ClickHouse phản hồi Ok.pg_isready phản hồi accepting connections. Lỗi connection refused trên 8123 nghĩa là container vẫn đang khởi động hoặc đã dừng. docker compose logs clickhouse cho biết trường hợp nào xảy ra, còn docker inspect $(docker compose ps -q clickhouse) | grep -i oomkilled báo true khi kernel kill process vì thiếu bộ nhớ. Điều này cho thấy máy quá nhỏ, không phải cấu hình của bạn bị sai.

Tiếp theo là migration và các ứng dụng:

pnpm --filter @superlog/db db:migrate
pnpm dev

Lưu ý cổng: 5434, không phải 5432. Compose file publish Postgres trên cổng 5434 để không xung đột với Postgres đã cài trên host, còn các file .env.example của app cũng khớp với thiết lập này, kèm DATABASE_URL=postgres://postgres:postgres@localhost:5434/superlog. Nếu trỏ migration đến 5432 trên máy đã chạy Postgres, bạn có thể nhận lỗi connection refused hoặc, nghiêm trọng hơn, migration được áp dụng vào nhầm database.

pnpm dev khởi động 4 process được liệt kê trong Procfile của repository: api, web, worker và proxy. Mỗi process tee output vào tmp/logs/, vì vậy tail -f tmp/logs/proxy.log là nơi bạn monitor ingest. README đặt web app trên http://localhost:5173, API trên http://localhost:4100 và OTLP intake trên http://localhost:4101.

Hãy xác nhận process thực sự đang bind cổng nào trước khi trỏ bất kỳ thành phần nào vào đó:

ss -lntp | grep -E '4100|4101|5173'
curl -sS http://127.0.0.1:4101/health

Điều này sẽ quan trọng ở phần sau. Proxy đọc cổng của nó từ biến môi trường PORT và dùng 4000 nếu PORT chưa được set. Development stack tự set biến này cho bạn. systemd unit do bạn tự viết thì không, nên exporter trỏ đến 4101 trong khi proxy đang listen trên 4000 sẽ lỗi connection refused mà không cung cấp thêm manh mối nào.

Gửi một trace, tạo một lỗi, xem một incident

Tạo một project trong web app rồi sao chép ingest key của project đó. Intake xác thực mọi request bằng key này, nên telemetry gửi không kèm key sẽ không bao giờ đến được ClickHouse.

Trỏ bất kỳ OpenTelemetry SDK nào vào intake bằng các biến môi trường tiêu chuẩn:

export OTEL_SERVICE_NAME=checkout-api
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4101
export OTEL_EXPORTER_OTLP_HEADERS='x-api-key=YOUR_INGEST_KEY'

Intake đọc key từ header x-api-key và cũng chấp nhận authorization: bearer YOUR_INGEST_KEY nếu exporter của bạn dễ cấu hình theo cách đó hơn. Nó phục vụ 3 path OTLP tiêu chuẩn là /v1/traces, /v1/logs/v1/metrics, cùng với /health.

Có một lỗi dễ nhầm cần lưu ý. OTEL_EXPORTER_OTLP_ENDPOINT là base URL và SDK sẽ nối signal path vào đó. Các biến dành riêng cho từng signal như OTEL_EXPORTER_OTLP_TRACES_ENDPOINT được dùng đúng như đã ghi, không nối thêm path. Nếu đặt biến dành riêng cho signal thành http://127.0.0.1:4101 thì mọi lần export sẽ gửi đến /. Đây không phải route, nên không có dữ liệu nào đến nơi và SDK ghi log export failure trong khi app vẫn có vẻ hoạt động bình thường.

Với một service Node, đường đi không cần thêm code là đủ để kiểm tra pipeline:

npm install @opentelemetry/api @opentelemetry/auto-instrumentations-node
node --require @opentelemetry/auto-instrumentations-node/register server.js

Bây giờ cố ý tạo lỗi. Bất kỳ route nào phát sinh exception đều được:

curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/boom

Kiểm tra từng chặng theo thứ tự, vì khoảng trống đầu tiên cho biết chặng nào bị lỗi:

tail -n 50 tmp/logs/proxy.log
docker compose exec clickhouse clickhouse-client --database superlog --query 'SELECT count() FROM otel_traces'

Số lượng trong otel_traces tăng nhưng web app không có dữ liệu là dấu hiệu project bị nhầm, nên hãy kiểm tra ingest key thuộc project nào. Số lượng không tăng nhưng proxy log có hoạt động cho thấy vấn đề nằm ở collector hoặc bước ghi vào ClickHouse, nên hãy đọc docker compose logs collector. Nếu proxy log hoàn toàn không có hoạt động thì exporter chưa đến được intake: sai port, sai path hoặc key bị từ chối.

Trong web app, các lỗi lặp lại này xuất hiện thành một incident thay vì mỗi request một dòng. Superlog tạo fingerprint cho các signal đến và gom những signal trùng khớp, nhờ đó inbox chứa 1 incident thay vì 4,000 lỗi giống hệt nhau. Sau đó agent ghi phần điều tra lên trên group đó.

Bước điều tra gọi đến một model, nên worker phải được cấu hình model provider. Hãy lấy tên các biến đó từ file .env.example bên trong thư mục của từng app thuộc commit bạn đã pin, thay vì lấy từ tài liệu bên ngoài, vì chúng thay đổi theo main. Điều tương tự cũng áp dụng cho các integration GitHub và Sentry. Mỗi integration có tài liệu thiết lập riêng tại docs/github-app-setup.mddocs/sentry-app-setup.md, còn payload của webhook được tài liệu hóa tại docs/webhooks.md.

Giữ endpoint tiếp nhận ở chế độ riêng tư và để agent chỉ có quyền đọc

Docker mặc định publish các cổng của container trên 0.0.0.0. Các cổng này bypass ufw vì Docker tự ghi rule vào chain DOCKER-USER, và các rule này được đánh giá trước khi ufw xử lý packet. Trên VPS có public IP, file compose khi được cung cấp sẽ đặt ClickHouse HTTP trên cổng 8123 và Postgres trên cổng 5434, khiến Internet có thể truy cập chúng. Credential trong file đó là giá trị mặc định cho môi trường development: user ClickHouse là default với password rỗng, còn Postgres dùng postgres làm cả user và password.

Bind các cổng này vào loopback. Mọi published port trong file compose đều lấy phía host từ một biến môi trường, nên chỉ cần tạo file .env tại thư mục gốc của repository:

POSTGRES_HOST_PORT=127.0.0.1:5434
CLICKHOUSE_HTTP_HOST_PORT=127.0.0.1:8123
CLICKHOUSE_TCP_HOST_PORT=127.0.0.1:9000
COLLECTOR_GRPC_HOST_PORT=127.0.0.1:4317
COLLECTOR_HTTP_HOST_PORT=127.0.0.1:4318

Xác minh kết quả trước khi tin tưởng cấu hình, sau đó recreate các container:

docker compose config
docker compose up -d
ss -lntp | grep -E '5434|8123|9000|4317|4318'

docker compose config in ra file đã được resolve, nên bạn có thể đọc 127.0.0.1:5434:5432 thay vì đoán. Khi đó, ss phải hiển thị 127.0.0.1:5434 và không bao giờ hiển thị 0.0.0.0:5434. Không cố sửa việc này bằng file compose override có khai báo lại ports, vì Compose nối các danh sách port giữa các file thay vì thay thế chúng. Kết quả là cả hai binding cùng tồn tại và binding public vẫn mở.

Endpoint tiếp nhận cũng cần được bảo vệ tương tự. Ingest key được gửi trong header, nên cần có TLS (transport layer security) ở phía trước: terminate TLS trong nginx hoặc Caddy trước proxy, hoặc giữ ingest trong private network hay tunnel WireGuard. Web app trên cổng 5173 là Vite development server và hoàn toàn không nên public ra Internet.

Tiếp theo là chính agent. Điểm chính Superlog đưa ra là agent sẽ điều tra và đề xuất cách sửa. Từ quan trọng ở đây là “đề xuất”. Giữ agent ở chế độ read only đối với production cho đến khi bạn đã theo dõi nó xử lý một vài incident thực tế. Cấp cho GitHub App các read scope và cho phép app mở pull request để bạn review. Agent đọc telemetry và ghi ra patch là hữu ích. Agent có thể restart service của bạn là một mức rủi ro khác hẳn. Đây phải là quyết định có chủ đích của bạn, không phải quyền mặc định được kế thừa. Chi phí cũng cần được chú ý tương tự vì mỗi lần điều tra đều là một model call: hãy lập ngân sách cho chi phí agent trên VPS trước khi trỏ nó vào hệ thống production nhiều nhiễu, đồng thời ghi lại chính xác những gì agent đã thực hiện để pull request bất ngờ vẫn có audit trail đi kèm.

Các lỗi bạn sẽ gặp và chuỗi dùng để gọi tên chúng

  • ERR_PNPM_UNSUPPORTED_ENGINE trong lúc pnpm install có nghĩa là Node cũ hơn 20. node -v xác nhận điều đó trên một dòng.
  • ECONNREFUSED 127.0.0.1:5434 trong lúc migration có nghĩa là compose stack chưa chạy, hoặc DATABASE_URL chỉ sai port.
  • ClickHouse khởi động lại liên tục thường là do thiếu memory. Đọc docker compose logs clickhouse, rồi kiểm tra container để xác nhận OOMKilled đang là true.
  • Exporter báo thành công nhưng web app vẫn trống thường có nghĩa là dữ liệu đi thẳng đến collector tại 4318, bỏ qua việc gắn project mà proxy thực hiện.
  • Connection refused trên 4101 trong bản cài đặt production có nghĩa là proxy đã fallback về PORT=4000. Đặt rõ PORT trong unit file.
  • docker compose ps hiển thị 0.0.0.0:8123 có nghĩa là các binding loopback của bạn không có hiệu lực. Chạy docker compose config và đọc các port đã được resolve.

Flawless, HyperProbe và vị trí của Superlog

Danh mục này còn mới, và các công cụ khác nhau ở phạm vi mà agent được phép truy cập. Flawless là công cụ AI SRE (site reliability engineering) mã nguồn mở, tập trung vào Kubernetes. Công cụ này đọc dữ liệu từ stack Prometheus, Loki và Grafana có sẵn thay vì tự quản lý pipeline. HyperProbe đi theo hướng ngược lại: đây là sản phẩm hosted, vẫn closed source tính đến tháng 8 năm 2026. Nó đặt các probe chỉ đọc bên trong một process đang chạy để thu thập trạng thái biến, rồi cung cấp trạng thái đó cho assistant qua MCP (model context protocol).

Superlog nằm giữa hai hướng này. Nó tự quản lý toàn bộ pipeline, từ khâu tiếp nhận OTLP đến lưu trữ trong ClickHouse, và đặt agent ở bước triage thay vì bước sửa lỗi. Vì vậy, self-host Superlog là một quyết định về hạ tầng, không phải việc chạy một container rồi bỏ đó. Khi chạy Superlog, bạn đang vận hành một column store. Nó cần được quản trị cẩn thận như mọi database khác mà bạn tự sở hữu.

FAQ

Superlog tự host cần bao nhiêu RAM?

Dự trù 8 GB RAM, 4 vCPU và 40 GB disk cho một node khi lưu lượng ingest thấp. Stack này gồm Postgres, ClickHouse, một OpenTelemetry collector và 4 tiến trình Node; ClickHouse cần đủ headroom. VPS 1 GB hoặc 2 GB là không đủ: riêng pnpm install đã nặng, và khi có tải, ClickHouse có thể bị kernel OOM killer dừng lại. Hãy đo số liệu thực tế của hệ thống bằng docker stats --no-streamfree -m thay vì tin vào bất kỳ con số nào được công bố, kể cả con số trong mục này.

Tôi cần trỏ OTLP exporter đến port nào?

Hãy trỏ đến intake proxy của Superlog, được README cấu hình trên http://localhost:4101. Proxy này phục vụ /v1/traces, /v1/logs/v1/metrics, đồng thời xác thực bằng ingest key của project, lấy từ header x-api-key hoặc header authorization: bearer. Port 4318 là port của OpenTelemetry collector bên dưới. Export trực tiếp đến đó sẽ bỏ qua proxy, trong khi proxy là thành phần gắn project id vào dữ liệu. Proxy dùng port 4000 làm giá trị dự phòng khi PORT chưa được đặt. Vì vậy, hãy chạy ss -lntp và xác nhận port mà proxy đã bind trước khi giả định đó là 4101.

Superlog có thay thế được Uptime Kuma hoặc Zabbix không?

Không. Uptime Kuma kiểm tra endpoint có phản hồi từ bên ngoài mạng của bạn hay không. Zabbix theo dõi metric của host và service theo các ngưỡng bạn đặt. Superlog tiếp nhận trace, log và metric do ứng dụng phát ra, rồi nhóm các lỗi lặp lại thành incident. Hãy dùng thêm một uptime probe bên ngoài, vì probe chạy ở nơi khác vẫn báo cáo được khi chính máy chủ đang chạy telemetry pipeline bị hỏng.

Agent của Superlog có thể thay đổi hệ thống production của tôi không?

Chỉ khi bạn cấp quyền cho nó. Output của agent là kết quả điều tra và thay đổi được đề xuất để con người review. Ban đầu, hãy chỉ cấp các read scope cho GitHub App và giữ mọi credential mà worker sử dụng ở phạm vi chỉ đọc. Quyền ghi vào production phải là một quyết định riêng và có chủ đích, vì agent có thể restart service đòi hỏi mức cam kết lớn hơn nhiều so với agent chỉ đọc telemetry và tạo patch để review.

Tôi nên pin một commit hay theo dõi main?

Hãy pin một commit. Tính đến August 2026, repository chưa có release tag, nên main là target duy nhất có tính thay đổi và repository này cập nhật vài commit mỗi tuần. Hãy ghi lại SHA đã test, deploy đúng commit đó và đọc diff trước khi cập nhật. git log --oneline <old-sha>..main là nơi review, còn các file .env.example theo từng app là nơi đầu tiên cần kiểm tra để tìm các biến mới bắt buộc sau mỗi lần bump.

#superlog#observability#opentelemetry#clickhouse#ai-sre