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

Tự host LiveContext: VPS 8 GB, Docker và backup

Hướng dẫn tự host LiveContext CE với 6 container Docker và backend Java cần 8 GB RAM: pin version, dùng Traefik, backup cả hai store và lưu ý chỉ hỗ trợ x86_64.

LiveContext là gì và chi phí vận hành

Để tự host LiveContext, bạn cần một VPS có khoảng 8 GB RAM. LiveContext CE là nền tảng tự động hóa mã nguồn mở, chạy các AI agent bên trong chính quy trình tự động hóa. Phần mềm được cung cấp dưới dạng một Docker Compose stack gồm 6 container, xây dựng quanh backend Java. README upstream yêu cầu tối thiểu 4 GB và khuyến nghị 8 GB RAM. File compose cho thấy lượng RAM được phân bổ ở đâu.

Project này nằm tại livecontext-ai/livecontext-ce trên GitHub và được cấp phép theo AGPL-3.0. Bản release hiện tại tính đến tháng 8 năm 2026 là v0.2.11, được phát hành ngày 3 tháng 8 năm 2026. Mọi image chỉ được build cho linux/amd64, nên không thể dùng các gói Arm giá rẻ. Tutorial này cố định tag đó, đặt stack phía sau reverse proxy và hướng dẫn quy trình backup mà tài liệu upstream không đề cập.

Chọn cấu hình VPS trước khi tự host LiveContext

Mọi service trong file compose được phát hành đều có giới hạn memory rõ ràng, nên bạn có thể chọn cấu hình máy trước khi thuê VPS. Đây là các giới hạn được ghi trong file compose v0.2.11, không phải mức sử dụng thực tế.

ChartMemory limits in the LiveContext CE v0.2.11 compose file, MB
The data behind this chart
[
  {
    "label": "livecontext (backend)",
    "memory_limit_mb": 1536
  },
  {
    "label": "bridge",
    "memory_limit_mb": 512
  },
  {
    "label": "redis",
    "memory_limit_mb": 384
  },
  {
    "label": "postgres",
    "memory_limit_mb": 256
  },
  {
    "label": "minio",
    "memory_limit_mb": 256
  },
  {
    "label": "websearch (optional)",
    "memory_limit_mb": 2048
  },
  {
    "label": "searxng (optional)",
    "memory_limit_mb": 512
  },
  {
    "label": "renderer (optional)",
    "memory_limit_mb": 1024
  }
]

Chỉ riêng backend đã bị giới hạn ở 1536 MB. Giới hạn này áp dụng cho một tiến trình Java 21, nên JVM sẽ tăng memory đến gần mức đó và giữ lại. Năm service cơ sở cộng lại chỉ dưới 3 GB, còn frontend không có giới hạn nên sẽ dùng lượng memory Node yêu cầu. Trên VPS 4 GB, kernel và page cache gần như không còn memory. Vì vậy, 4 GB được ghi là mức tối thiểu chứ không phải cấu hình khuyến nghị.

Các profile tùy chọn là lý do cần VPS 8 GB. Profile browser agent thêm một container Chromium bị giới hạn ở 2048 MB, cùng với một instance tìm kiếm SearXNG. Profile renderer thêm 1024 MB cho screenshot và PDF. Cả hai không khởi động nếu bạn chưa enable profile tương ứng, nên hãy để cả hai tắt cho đến khi cần. Container SearXNG đó tồn tại để làm search backend cho agent. Vì vậy, các trang mà nó trả về sẽ xuất hiện trong prompt dưới dạng text không đáng tin cậy. Đây là ranh giới tin cậy mà việc cung cấp tìm kiếm web SearXNG cho AI agent mô tả chi tiết.

Nếu bạn đã chạy n8n, hãy lên kế hoạch thay thế nó thay vì chạy thêm. Stack trong hướng dẫn chạy n8n trên VPS với Docker và HTTPS của chúng tôi gồm một tiến trình Node cùng với Postgres và chạy ổn định trên máy cấu hình nhỏ. Chỉ riêng backend của LiveContext đã cần nhiều memory hơn toàn bộ stack đó. Hai nền tảng automation trên cùng một VPS 8 GB sẽ vẫn chạy được cho đến khi cả hai cùng chạy job trong một phút. Nếu dùng chung host, hãy đặt giới hạn rõ ràng cho mọi thành phần còn lại theo phương pháp trong bài viết về cách đặt giới hạn memory trong Docker Compose của chúng tôi, để một workflow chạy mất kiểm soát không làm cả máy ngừng hoạt động.

Cài đặt LiveContext bằng Docker Compose và ghim vào một tag

Bắt đầu với một VPS Ubuntu 24.04 mới cài, có Docker Engine 24 trở lên và Compose v2. Nếu Docker chưa được cài, trước tiên hãy làm theo hướng dẫn cơ bản về Docker Compose cho VPS của chúng tôi, rồi quay lại đây.

README cung cấp npx livecontext để khởi động bằng một dòng lệnh. Cách này phù hợp trên laptop. Trên server, bạn nên đặt file compose trong một thư mục do mình quản lý. Khi đó, nâng cấp chỉ cần checkout một git tag và bạn có thể xem chính xác những gì đã thay đổi.

sudo apt update && sudo apt install -y git
git clone https://github.com/livecontext-ai/livecontext-ce.git
cd livecontext-ce
git tag --list 'v*' | tail -5
git checkout v0.2.11
cp docker/.env.ce.example docker/.env.ce
chmod 600 docker/.env.ce

File compose đã ghim mọi image vào release tag tương ứng, chẳng hạn ghcr.io/livecontext-ai/livecontext-ce:v0.2.11. Checkout đúng git tag giúp file compose và các image luôn đồng bộ, vì file compose của v0.2.11 được viết để chạy với những image đó. Không sửa các tag thành latest. Tag latest có thể thay đổi mà bạn không biết, còn backend chạy database migration ở mỗi lần khởi động. Vì vậy, một lần pull ngoài ý muốn có thể nâng schema lúc 3 giờ sáng và bạn chỉ có thể quay lại bằng cách restore.

Sửa docker/.env.ce trước lần khởi động đầu tiên (phần tiếp theo liệt kê những mục cần thay đổi), rồi khởi động stack.

docker compose --env-file docker/.env.ce up -d
docker compose --env-file docker/.env.ce ps

Dùng cùng flag --env-file trong mọi lệnh compose của hướng dẫn này. Compose đọc lại file đó ở mỗi lần chạy. Vì vậy, nếu thiếu flag, lệnh sẽ dùng các giá trị mặc định được ghi sẵn trong file compose và có thể publish các cổng khác với những cổng bạn đã cấu hình.

Healthcheck của backend có start_period là 120s và polling /actuator/health. Vì vậy, docker compose ps sẽ báo service livecontext ở trạng thái health: starting trong khoảng 2 phút đầu, trong khi schema migration và quá trình đăng ký tool đang chạy. Đây là trạng thái bình thường. Kiểm tra nhanh trên server:

curl -s localhost:8080/actuator/health

Lệnh này phải in ra {"status":"UP"}. Khi thấy kết quả đó, mở web UI trên port 3000. Tài khoản đầu tiên bạn tạo sẽ trở thành admin, vì vậy hãy tạo tài khoản của bạn trước khi người khác có thể truy cập port này. Đây là lý do quan trọng nhất để không publish port 3000 ra Internet ngay từ ngày đầu.

Các giá trị env bạn phải thay đổi

File mẫu có sẵn các giá trị mặc định để stack khởi động trên laptop. Một số giá trị không an toàn khi dùng trên server public.

POSTGRES_PASSWORD=<random>
MINIO_ROOT_USER=<not minioadmin>
MINIO_ROOT_PASSWORD=<random>
CREDENTIAL_ENCRYPTION_PASSWORD=<random>
CREDENTIAL_ENCRYPTION_SALT=<random>
ANTHROPIC_API_KEY=sk-ant-...
FRONTEND_PORT=3000
BACKEND_PORT=8080
GATEWAY_PUBLIC_URL=https://lc-api.example.com

Tạo từng giá trị ngẫu nhiên bằng openssl rand -base64 32. Lưu ý các giá trị dễ gây sự cố:

  • POSTGRES_PASSWORDMINIO_ROOT_PASSWORD được phát hành với giá trị postgresminioadmin. Không database port nào được publish ra host, nên chúng không bị expose trực tiếp. Tuy nhiên, mọi container bạn attach vào cùng network sau này đều có thể truy cập cả hai bằng giá trị mặc định được tài liệu ghi rõ.
  • CREDENTIAL_ENCRYPTION_PASSWORDCREDENTIAL_ENCRYPTION_SALT sẽ được tự động tạo khi để trống. Bạn nên tự đặt chúng. Credentials mà workflow lưu được mã hóa bằng cặp giá trị này. Vì vậy, nếu restore database dump trên máy mới mà không có cùng password và salt, các credential row sẽ không thể được đọc. Chỉ đặt chúng một lần, sau đó xem docker/.env.ce là một phần của backup.
  • FRONTEND_PORTBACKEND_PORT được thay thế vào port mapping dưới dạng ${FRONTEND_PORT:-3000}:3000${BACKEND_PORT:-8080}:8080. File env mẫu đặt rõ cả hai giá trị, và các giá trị được cung cấp không phải lúc nào cũng là 3000 và 8080. Hãy đọc bản sao của bạn thay vì giả định.
  • GATEWAY_PUBLIC_URL là origin mà backend cung cấp cho browser. Giá trị này quan trọng ngay khi có reverse proxy. Xem phần tiếp theo.
  • Các model key (ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY và tùy chọn MISTRAL_API_KEY hoặc DEEPSEEK_API_KEY) nằm trong file này dưới dạng plain text. Chỉ điền provider bạn thực sự sử dụng.

Chức năng của sáu container

  • postgres chạy pgvector/pgvector:pg16 dưới dạng container livecontext-db và lưu database có tên livecontext. Extension pgvector được dùng để tìm kiếm embedding, nên image postgres:16 thông thường sẽ không đáp ứng được.
  • redis chạy redis:7-alpine với appendonly yes--maxmemory-policy noeviction. Đây là chính sách có chủ đích: Redis lưu queue và trạng thái thực thi ở đây. Khi đạt giới hạn bộ nhớ, Redis trả về lỗi cho tiến trình ghi thay vì âm thầm xóa key. Lỗi có thể nhìn thấy vẫn tốt hơn công việc biến mất mà không có thông báo.
  • minio là object store tương thích với S3 cho các file đi qua workflow. Một container minio-init chạy một lần sẽ thực thi mc mb myminio/workflow-files --ignore-existing khi khởi động, tạo bucket rồi thoát. Thấy minio-init ở trạng thái exited (0) trong docker compose ps là trạng thái bình thường.
  • bridge chứa các CLI adapter và công cụ MCP (model context protocol). Nó lắng nghe trên cổng 8093 trong Docker network và không được publish ra host.
  • livecontext là backend, một monolith Java 21 trên cổng 8080. Nó chạy workflow engine, scheduler và agent.
  • frontend là web UI Next.js trên cổng 3000. Chỉ hai container cuối được publish ra host.

State được lưu trong năm named volume: livecontext_data cho Postgres, livecontext_redis, livecontext_minio, livecontext_keyslivecontext_logs. Compose thêm project name vào đầu tên volume. Mặc định, project name là tên thư mục, nên volume thực tế trên disk sẽ có tên tương tự livecontext-ce_livecontext_minio. Chạy docker volume ls và sao chép đúng tên trước khi viết backup script sử dụng các volume này.

docker compose down -v xóa cả năm volume. Đây là cách được tài liệu hướng dẫn để bắt đầu lại, nhưng cũng là cách nhanh nhất để mất toàn bộ workflow bạn đã tạo. -v là phần tạo nên toàn bộ khác biệt.

Đặt ứng dụng sau Traefik thay vì publish port 3000

Publish các port 3000 và 8080 trên một VPS public sẽ đưa ứng dụng ra ngoài mà không có TLS (transport layer security) và không có lớp kiểm soát phía trước trang đăng ký admin. Một rule ufw riêng lẻ là chưa đủ, vì Docker chèn các rule iptables riêng cho những port được publish vào trước chain do ufw quản lý. Vì vậy, port được publish đến 0.0.0.0 vẫn truy cập được dù ufw báo port đó bị deny.

Cách xử lý gọn nhất là không publish port nào, rồi để proxy truy cập các container qua một Docker network dùng chung. Tạo docker-compose.override.yml tại thư mục gốc của repo:

services:
  frontend:
    ports: !override []
    networks:
      - default
      - proxy
  livecontext:
    ports: !override []
    networks:
      - default
      - proxy

networks:
  proxy:
    external: true

Có 2 chi tiết quyết định cấu hình này có hoạt động hay không. !override thay thế danh sách ports thay vì gộp với danh sách hiện có. Tính năng này cần Compose v2.24 hoặc mới hơn. Kiểm tra bằng docker compose version, vì trên bản Compose cũ hơn, 2 danh sách sẽ bị gộp và các port vẫn được publish. Ngoài ra, default phải tiếp tục có trong từng danh sách networks. Khi đặt tên cho bất kỳ network nào, Compose sẽ thay thế network mặc định. Nếu bỏ network mặc định khỏi danh sách, frontend sẽ mất kết nối đến Postgres và Redis. Xác nhận kết quả sau khi gộp trước khi khởi động:

docker compose --env-file docker/.env.ce config

Các router, certificate resolver và redirect từ HTTP sang HTTPS giống với những app khác. Vì vậy, hãy làm theo hướng dẫn reverse proxy Traefik để chạy nhiều app trên cùng một VPS thay vì viết cấu hình TLS mới ở đây. Route một hostname đến frontend trên port 3000 và hostname thứ hai đến livecontext trên port 8080.

Hostname thứ hai là bắt buộc. Web UI gọi backend từ browser, nên backend cần một origin riêng mà browser có thể truy cập. Đặt GATEWAY_PUBLIC_URL trong docker/.env.ce thành URL của backend, ví dụ https://lc-api.example.com. Nếu bỏ qua, trang vẫn tải bình thường nhưng mọi thao tác đều fail, vì UI lấy origin của backend từ địa chỉ bạn đã mở và đang gọi đến một port mà proxy không publish.

Vì trang đăng ký cho phép người đầu tiên truy cập tạo tài khoản, bạn nên đặt forward auth trên frontend router để không ai nhìn thấy trang đó nếu chưa xác thực tại proxy. Đây là chức năng mà chạy Authentik làm lớp SSO riêng của bạn bổ sung trên cùng cấu hình Traefik.

Vị trí đặt model key và lý do instance nhàn rỗi vẫn tốn tiền

Agent chạy bên trong hệ thống automation này, nên chi phí khác với một workflow tool thông thường. Provider key được đặt trong docker/.env.ce dưới dạng ANTHROPIC_API_KEY hoặc OPENAI_API_KEY, được backend và bridge đọc khi khởi động, và áp dụng cho toàn bộ instance. Key này không được giới hạn theo từng user. Bất kỳ ai có account trên instance của bạn và có thể tạo agent đều có thể sử dụng key đó để phát sinh chi phí. Người đăng ký đầu tiên là admin.

Ba thói quen sau giúp chi phí dễ dự đoán hơn. Tạo một provider key riêng cho VPS này để có thể revoke key mà không ảnh hưởng đến các hệ thống khác. Đặt hard spend cap trong provider console, vì đó là giới hạn duy nhất nằm ngoài máy bạn đang bảo vệ. Sau đó sử dụng per-agent credit budget và per-agent metrics do LiveContext cung cấp, để một loop không thể sử dụng hết key trước khi bạn phát hiện.

Chi phí khi nhàn rỗi không bằng 0 nếu agent chạy theo schedule. Schedule trigger vẫn chạy dù không có ai theo dõi, và mỗi lần chạy đều gửi token. Schedule 5 phút chạy 288 lần mỗi ngày. Một agent đọc một trang rồi quyết định không làm gì vẫn phải trả chi phí đọc trang đó. Ban đầu, hãy cấu hình agent dùng webhook hoặc chat trigger, theo dõi chi phí thực tế trong một tuần, rồi chuyển sang schedule sau khi biết chi phí cho mỗi lần chạy.

Sao lưu Postgres và object store

Có hai data store và một secret. Mất bất kỳ thành phần nào trong ba thành phần này đều làm mất instance của bạn. Sao lưu database và bucket trong cùng một khoảng thời gian, khi backend đã dừng, để không có file nào được ghi sau khi row tương ứng trong database đã được dump.

cd ~/livecontext-ce
mkdir -p ~/backups
docker compose --env-file docker/.env.ce stop livecontext frontend
docker compose --env-file docker/.env.ce exec -T postgres \
  pg_dump -U postgres -d livecontext --clean --if-exists \
  | gzip > ~/backups/livecontext-db-$(date +%F).sql.gz

Nếu bạn đã thay đổi DB_USERNAME, hãy dùng giá trị bạn đã đặt cho DB_USERNAME thay cho postgres. Sau đó sao chép volume của object store, dùng tên có tiền tố do docker volume ls in ra:

docker run --rm \
  -v livecontext-ce_livecontext_minio:/data \
  -v ~/backups:/backup \
  alpine tar czf /backup/livecontext-minio-$(date +%F).tgz -C /data .
docker compose --env-file docker/.env.ce start livecontext frontend
cp docker/.env.ce ~/backups/env.ce.$(date +%F)

Kiểm tra dump không rỗng trước khi tin cậy nó: gunzip -c ~/backups/livecontext-db-*.sql.gz | head -20 phải hiển thị các câu lệnh CREATE TABLEDROP TABLE, không phải một lỗi chỉ có một dòng. Sau đó sao chép cả ba file ra khỏi server. Backup chỉ nằm trên chính máy mà nó bảo vệ thì không phải là backup.

Để restore sang một máy mới, cài cùng tag, đưa docker/.env.ce đã lưu trở lại để password và salt dùng cho mã hóa credential khớp nhau, khởi động stack một lần để các volume được tạo, dừng backend, rồi nạp dump:

gunzip -c livecontext-db-2026-08-10.sql.gz \
  | docker compose --env-file docker/.env.ce exec -T postgres psql -U postgres -d livecontext

Nâng cấp và cách khôi phục khi có sự cố

Luôn tạo dump trước mỗi lần nâng cấp. Backend áp dụng schema migration khi khởi động và migration chỉ tiến về phía trước. Vì vậy, nếu checkout tag cũ sau một lần nâng cấp lỗi, code cũ sẽ chạy trên schema mới hơn. Rollback nghĩa là khôi phục dump. Đó là lý do phải tạo dump trước.

cd ~/livecontext-ce
git fetch --tags
git tag --list 'v*' | tail -5
TAG=v0.2.11
git checkout "$TAG"
docker compose --env-file docker/.env.ce pull
docker compose --env-file docker/.env.ce up -d
docker compose --env-file docker/.env.ce logs -f livecontext

Đặt TAG thành tag bạn chọn từ danh sách do lệnh thứ ba in ra. Theo dõi log của backend cho đến khi health endpoint phản hồi trở lại. docker-compose.override.yml của bạn không được track, nên git checkout sẽ giữ nguyên file này. Tuy nhiên, hãy đọc diff trên docker-compose.yml giữa các tag, vì service mới hoặc service được đổi tên có thể khiến override của bạn bị lỗi thời mà không có thông báo lỗi.

Các tình huống lỗi và chuỗi bạn sẽ thấy

Một container liên tục restart và docker compose ps hiển thị exited (137). Đây là kernel out-of-memory killer. docker inspect livecontext-app xác nhận điều đó với "OOMKilled": true trong block trạng thái. Backend đã chạm giới hạn 1536M, hoặc host đã hết memory trước. Kiểm tra free -m trước khi tăng bất kỳ giới hạn nào. Tăng giới hạn container trên host không còn memory trống chỉ chuyển việc kill sang một container khác.

Lệnh pull thất bại với no matching manifest for linux/arm64/v8 in the manifest list entries. Các image chỉ được phát hành cho linux/amd64. Arm VPS không thể chạy stack này từ các image đã phát hành. Emulation qua QEMU quá chậm đối với JVM và Chromium. Chuyển sang gói x86.

Bind for 0.0.0.0:3000 failed: port is already allocated. Một tiến trình khác trên host đang giữ port đó. Đổi FRONTEND_PORT trong docker/.env.ce, hoặc áp dụng override ở trên và không publish port nào cả.

UI đã chạy nhưng request đăng nhập thất bại sau khi bạn thêm proxy. Browser đang gọi backend trên một origin mà proxy không phục vụ. Mở tab network của browser và xem host của request bị lỗi. Đặt GATEWAY_PUBLIC_URL thành URL public của backend rồi recreate frontend container, vì giá trị này được đọc khi container khởi động.

Mọi thứ đều healthy nhưng các file upload trong workflow biến mất. Kiểm tra để đảm bảo minio-init hiển thị exited (0) thay vì mã khác 0. Nếu bucket workflow-files chưa từng được tạo, backend không có nơi để lưu object.

Chọn LiveContext hoặc n8n

Chọn LiveContext khi agent là trọng tâm: bạn muốn model xây dựng và chạy automation, đồng thời chấp nhận một máy 8 GB và một Java service làm chi phí đánh đổi. Chọn n8n khi bạn muốn các workflow có tính quyết định, một thư viện node lớn và footprint có thể dùng chung VPS với các service khác. Các số phiên bản ở đây còn mới, v0.2.11 tính đến tháng 8 năm 2026, vì vậy hãy pin tag và đọc release notes trước mỗi lần upgrade. Để xem phạm vi rộng hơn, bao gồm cả các tool nằm giữa hai lựa chọn này, hãy xem bài tổng hợp các lựa chọn thay thế n8n tự host thay vì chỉ đọc phần so sánh hai công cụ này.

FAQ

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

Hãy dự trù 8 GB. README upstream ghi 4 GB là mức tối thiểu và 8 GB là mức khuyến nghị. File compose đi kèm cũng tương ứng với mức này: riêng backend bị giới hạn ở 1536 MB, còn năm service cơ sở cộng lại chỉ dưới 3 GB, chưa tính container frontend không giới hạn. Bật profile browser agent sẽ cần thêm 2048 MB cho Chromium và một container SearXNG. Khi đó, 8 GB không còn là mức tùy chọn.

Tôi có thể chạy LiveContext trên VPS Arm không?

Không. Mọi image được phát hành đều build cho linux/amd64, nên docker compose up trên gói Arm sẽ fail ngay khi pull với no matching manifest for linux/arm64/v8 in the manifest list entries. Về lý thuyết có thể chạy dưới QEMU emulation, nhưng trong thực tế hiệu năng sẽ không dùng được với workload JVM. Hãy chọn gói x86.

Tôi đặt model API key ở đâu?

Đặt trong docker/.env.ce, dưới dạng ANTHROPIC_API_KEY, OPENAI_API_KEY hoặc GOOGLE_API_KEY, trước lần start đầu tiên. Backend và bridge đọc key này khi khởi động. Key áp dụng cho toàn bộ instance, không chỉ một user. Giữ file ở mode 600. Dùng một key chỉ tạo cho server này để có thể revoke riêng key đó. Đồng thời đặt spend cap trong console của provider, vì đây là giới hạn duy nhất được áp dụng bên ngoài máy chủ.

Tôi sao lưu LiveContext như thế nào?

Có ba thứ cần sao lưu: một pg_dump của database livecontext, một bản sao của volume MinIO và file docker/.env.ce. Dừng các service livecontextfrontend trong khi tạo hai bản sao đầu tiên để database và object store giữ cùng một trạng thái. File env rất quan trọng vì các credential được lưu trong workflow được mã hóa bằng CREDENTIAL_ENCRYPTION_PASSWORDCREDENTIAL_ENCRYPTION_SALT. Nếu restore mà thiếu các giá trị này, các bản ghi credential vẫn còn nhưng không thành phần nào trên máy mới có thể đọc được.

Vì sao backend giữ ở trạng thái health: starting trong nhiều phút sau khi boot?

Compose healthcheck đặt start_period: 120s và polling /actuator/health. Vì vậy Docker báo service đang khởi động trong khi schema migration và quá trình đăng ký tool chạy. Lần boot đầu tiên mất từ hai đến ba phút là bình thường. Nếu service không bao giờ chuyển sang trạng thái healthy, hãy đọc docker compose logs -f livecontext. Một stack dừng ở bước migration thường đang trỏ đến database volume của một release mới hơn.